Annotation of nono/vm/romemu_luna88k.cpp, revision 1.1.1.15

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.11  root        7: //
1.1.1.13  root        8: // LUNA-88K の ROM エミュレーション
1.1.1.8   root        9: //
1.1.1.11  root       10: 
1.1.1.8   root       11: // IODevice
1.1.1.15! root       12: //  |
        !            13: //  +- ROMDevice (LoadROM()、ウェイト、マスク等を持つ)
        !            14: //  |   +- PROMDevice    (LUNA* の PROM)
        !            15: //  |   +- IPLROM1Device (X680x0 の IPLROM 後半)
        !            16: //  |   +- IPLROM2Device (X680x0 の IPLROM 前半)
        !            17: //  |   +- CGROMDevice   (X680x0 の CGROM)
        !            18: //  |   |
        !            19: //  |   +- ROMEmuDevice
        !            20: //  |       +- LunaPROMEmuDevice (LUNA PROM エミュレーションの共通部分)
        !            21: //  |       |   +- Luna1PROMEmuDevice      (LUNA-I の PROM エミュレーション)
        !            22: //  |       |   |
        !            23: //  |       |   | +----------------------+
        !            24: //  |       |   +-| Luna88kPROMEmuDevice | (LUNA-88K の PROM エミュレーション)
        !            25: //  |       |     +----------------------+
        !            26: //  |       |
        !            27: //  |       +- NewsROMEmuDevice    (NEWS の ROM エミュレーション)
        !            28: //  |       +- ROM30EmuDevice      (X68030 の ROM30 エミュレーション)
        !            29: //  |       +- Virt68kROMEmuDevice (virt-m68k の IPLROM 相当の何か)
        !            30: //  |
        !            31: //  +- PROM0Device   (LUNA* のブートページ切り替え用プロキシ)
        !            32: //  +- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ)
1.1.1.2   root       33: 
                     34: #include "romemu_luna88k.h"
1.1.1.5   root       35: #include "iodevstream.h"
1.1       root       36: #include "mainapp.h"
1.1.1.13  root       37: #include "mainram.h"
1.1       root       38: #include "memorystream.h"
1.1.1.7   root       39: #include "mk48t02.h"
1.1.1.8   root       40: #include "mpu88xx0.h"
1.1.1.14  root       41: #include "sysclk.h"
1.1.1.15! root       42: #include "sysctlr.h"
1.1       root       43: 
1.1.1.13  root       44: static bool luna88k_fline_callback(MPU88xx0Device *cpu, void *arg);
1.1.1.8   root       45: 
                     46: // m88k の命令コードを少し読みやすく書きたい。
                     47: // 必要なものは適宜足すこと。
                     48: enum class OPr {
                     49:        r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
                     50:        r8,  r9,  r10, r11, r12, r13, r14, r15,
                     51:        r16, r17, r18, r19, r20, r21, r22, r23,
                     52:        r24, r25, r26, r27, r28, r29, r30, r31,
                     53: };
                     54: #define r0     OPr::r0
                     55: #define r1     OPr::r1
                     56: #define r2     OPr::r2
                     57: #define r3     OPr::r3
                     58: #define r4     OPr::r4
                     59: #define r5     OPr::r5
                     60: #define r6     OPr::r6
                     61: #define r7     OPr::r7
                     62: #define r8     OPr::r8
                     63: #define r9     OPr::r9
                     64: #define r10    OPr::r10
1.1.1.14  root       65: #define r11    OPr::r11
1.1.1.8   root       66: enum OPm5 {
                     67:        eq0 = 0x02,
1.1.1.13  root       68:        ge0 = 0x03,
1.1.1.14  root       69:        lt0 = 0x0c,
1.1.1.8   root       70:        ne0 = 0x0d,
                     71: };
                     72: enum OPcr {
                     73:        psr = 0x01,
1.1.1.14  root       74:        snip = 0x05,
                     75:        sfip = 0x06,
                     76: };
                     77: enum CMPbits {
                     78:        CMP_EQ = 2,
                     79:        CMP_NE = 3,
                     80:        CMP_LT = 6,
1.1.1.8   root       81: };
                     82: 
1.1.1.11  root       83: #define USC  __unused static constexpr
                     84: 
                     85: USC uint32 OP3(uint32 base, uint32 rd, uint32 rs1, uint32 rs2) {
1.1.1.8   root       86:        return (base) | (rd << 21) | (rs1 << 16) | rs2;
                     87: }
1.1.1.11  root       88: USC uint32 OP4(uint32 base, uint32 rd, uint32 rs1,
1.1.1.8   root       89:        uint32 w, uint32 o) {
                     90:        return (base) | (rd << 21) | (rs1 << 16) | (w << 5) | o;
                     91: }
                     92: 
1.1.1.11  root       93: USC uint32 OP_addu(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8   root       94:        return OP3(0x60000000, (uint32)rd, (uint32)rs1, imm);
                     95: }
1.1.1.11  root       96: USC uint32 OP_addu(OPr rd, OPr rs1, OPr rs2) {
                     97:        return OP3(0xf4006000, (uint32)rd, (uint32)rs1, (uint32)rs2);
1.1.1.8   root       98: }
1.1.1.14  root       99: USC uint32 OP_and(OPr rd, OPr rs1, OPr rs2) {
                    100:        return OP3(0xf4004000, (uint32)rd, (uint32)rs1, (uint32)rs2);
                    101: }
                    102: USC uint32 OP_bb1(uint32 b, OPr rs1, uint32 d16) {
                    103:        return OP3(0xd8000000, b, (uint32)rs1, d16 & 0xffff);
                    104: }
1.1.1.11  root      105: USC uint32 OP_bcnd(OPm5 m5, OPr rs1, uint32 d16) {
                    106:        return OP3(0xe8000000, (uint32)m5, (uint32)rs1, d16 & 0xffff);
1.1.1.8   root      107: }
1.1.1.14  root      108: USC uint32 OP_br(uint32 d26) {
                    109:        return (0xc0000000 | (d26 & 0x03ffffff));
                    110: }
1.1.1.11  root      111: USC uint32 OP_bsr(uint32 d26) {
                    112:        return (0xc8000000 | (d26 & 0x03ffffff));
                    113: }
                    114: USC uint32 OP_clr(OPr rd, OPr rs1, uint32 w, uint32 o) {
1.1.1.8   root      115:        return OP4(0xf0008000, (uint32)rd, (uint32)rs1, w, o);
                    116: }
1.1.1.14  root      117: USC uint32 OP_cmp(OPr rd, OPr rs1, OPr rs2) {
                    118:        return OP3(0xf4007c00, (uint32)rd, (uint32)rs1, (uint32)rs2);
                    119: }
                    120: USC uint32 OP_extu(OPr rd, OPr rs1, uint32 w, uint32 o) {
                    121:        return OP4(0xf0009800, (uint32)rd, (uint32)rs1, w, o);
                    122: }
1.1.1.11  root      123: USC uint32 OP_jmp(OPr rs2) {
1.1.1.8   root      124:        return OP3(0xf400c000, 0, 0, (uint32)rs2);
                    125: }
1.1.1.11  root      126: USC uint32 OP_ld(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8   root      127:        return OP3(0x14000000, (uint32)rd, (uint32)rs1, imm);
                    128: }
1.1.1.11  root      129: USC uint32 OP_ldcr(OPr rd, uint32 crs) {
1.1.1.8   root      130:        return OP4(0x80004000, (uint32)rd, 0, crs, 0);
                    131: }
1.1.1.11  root      132: USC uint32 __unused OP_or(OPr rd, OPr rs1, OPr rs2) {
1.1.1.8   root      133:        return OP3(0xf4005800, (uint32)rd, (uint32)rs1, (uint32)rs2);
                    134: }
1.1.1.11  root      135: USC uint32 OP_or(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8   root      136:        return OP3(0x58000000, (uint32)rd, (uint32)rs1, imm);
                    137: }
1.1.1.14  root      138: USC uint32 OP_or_c(OPr rd, OPr rs1, OPr rs2) {
                    139:        return OP3(0xf4005c00, (uint32)rd, (uint32)rs1, (uint32)rs2);
                    140: }
1.1.1.11  root      141: USC uint32 OP_or_u(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8   root      142:        return OP3(0x5c000000, (uint32)rd, (uint32)rs1, imm);
                    143: }
1.1.1.11  root      144: USC uint32 OP_rte() {
1.1.1.8   root      145:        return 0xf400fc00;
                    146: }
1.1.1.14  root      147: USC uint32 OP_st(OPr rd, OPr rs1, uint32 imm) {
                    148:        return OP3(0x24000000, (uint32)rd, (uint32)rs1, imm);
                    149: }
1.1.1.11  root      150: USC uint32 OP_st(OPr rd, OPr rs1, OPr rs2) {
1.1.1.8   root      151:        return OP3(0xf4002400, (uint32)rd, (uint32)rs1, (uint32)rs2);
                    152: }
1.1.1.14  root      153: USC uint32 OP_st_b(OPr rd, OPr rs1, OPr rs2) {
                    154:        return OP3(0xf4002c00, (uint32)rd, (uint32)rs1, (uint32)rs2);
                    155: }
1.1.1.11  root      156: USC uint32 OP_stcr(OPr rs1, uint32 crd) {
1.1.1.8   root      157:        return OP4(0x80008000, 0, (uint32)rs1, crd, (uint32)rs1);
                    158: }
1.1.1.11  root      159: USC uint32 OP_doscall(OPr rd, OPr rs1, uint32 imm) {
1.1.1.8   root      160:        return OP3(0xfc000400, (uint32)rd, (uint32)rs1, imm);
                    161: }
1.1.1.14  root      162: #define SxIP_VALID     (0x0002)
1.1.1.8   root      163: #define DOS_GETCHAR    (1)
                    164: #define DOS_PUTCHAR    (2)
                    165: 
                    166: 
1.1       root      167: // コンストラクタ
                    168: Luna88kPROMEmuDevice::Luna88kPROMEmuDevice()
                    169: {
1.1.1.14  root      170:        machine_name = "LUNA-88K";
                    171: 
1.1.1.5   root      172:        // ROM の特定アドレスを読み出す人がいるかも知れないので、
                    173:        // サイズは実 ROM と同じにしておく。LUNA-I からの類推。
1.1.1.13  root      174:        uint devlen = 256 * 1024;
1.1.1.8   root      175:        imagebuf.reset(new uint8 [devlen]);
                    176:        memset(&imagebuf[0], 0, devlen);
                    177:        mem = &imagebuf[0];
                    178: 
                    179:        mask = devlen - 1;
1.1.1.2   root      180: 
1.1.1.5   root      181:        // プロンプトを初期化。
1.1.1.7   root      182:        prompt = default_prompt;
1.1       root      183: }
                    184: 
                    185: // デストラクタ
                    186: Luna88kPROMEmuDevice::~Luna88kPROMEmuDevice()
                    187: {
                    188: }
                    189: 
1.1.1.13  root      190: // 初期化
1.1       root      191: bool
                    192: Luna88kPROMEmuDevice::Init()
                    193: {
1.1.1.5   root      194:        if (inherited::Init() == false) {
                    195:                return false;
                    196:        }
                    197: 
1.1.1.14  root      198:        SysClkDevice *sysclk = GetSysClkDevice();
1.1.1.13  root      199: 
1.1.1.8   root      200:        // DOS call エミュレーションのコールバックを登録
1.1.1.14  root      201:        auto mpu88xx0 = GetMPU88xx0Device(mpu);
1.1.1.13  root      202:        mpu88xx0->SetFLineCallback(luna88k_fline_callback, this);
1.1.1.8   root      203: 
1.1.1.15! root      204:        MemoryStreamBE roms(imagebuf.get());
1.1       root      205: 
1.1.1.6   root      206:        // リセット時のブートページには ROM (これ) が見えている。
                    207:        // ROMIO_INIT へのアクセスでブートページを RAM に切り替えて、同時に RAM の
                    208:        // 0番地付近のベクタも作り直す。そのため、ここのベクタ1 以降 ($41000008〜)
                    209:        // をベクタとして参照することはないので、ベクタ0 の命令列がそのまま使い潰
                    210:        // してよい。というか2ワードでは 0番地から ROM まで飛べないので使わないと
                    211:        // 面倒くさい。一体どういう設計してんだ…。
                    212: 
1.1.1.8   root      213:        // ここからややアセンブラっぽいインデント
                    214: 
                    215:        // _START:
                    216:                // ここは 0番地。ここから _ROM_START へジャンプ
1.1.1.15! root      217:                roms.Write4(OP_or_u     (r6, r0, 0x4100));
        !           218:                roms.Write4(OP_or       (r6, r6, 0x000c));
        !           219:                roms.Write4(OP_jmp      (r6));
1.1.1.8   root      220: 
                    221:        // _ROM_START: (ここは ROM)
                    222:                // RAM に切り替え
1.1.1.15! root      223:                roms.Write4(OP_st       (r0, r6, r0));
1.1.1.8   root      224: 
1.1.1.11  root      225:                // 元の PSR を r10 に保存し、r9 に割り込み許可の値を作る
1.1.1.15! root      226:                roms.Write4(OP_ldcr     (r10, psr));
        !           227:                roms.Write4(OP_clr      (r9, r10, 2, 0));       // clear IND,SFRZ
        !           228:                roms.Write4(OP_stcr     (r9, psr));
        !           229:                roms.Write4(OP_or       (r11, r0, r0));         // r11 <- 0
1.1.1.8   root      230: 
1.1.1.15! root      231:                roms.Write4(OP_or_u     (r3, r0, ROMIO_BASE >> 16));
        !           232:                roms.Write4(OP_or       (r3, r3, ROMIO_BASE & 0xffff));
1.1.1.14  root      233:                // ROMIO_INIT を実行
1.1.1.15! root      234:                roms.Write4(OP_ld       (r0, r3, (ROMIO_INIT - ROMIO_BASE)));
        !           235:                roms.Write4(OP_ld       (r0, r3, (ROMIO_LOAD - ROMIO_BASE)));
        !           236:                roms.Write4(OP_br       (5));                           // _entry
1.1.1.8   root      237:        // _prompt:
1.1.1.15! root      238:                uint32 prompt = roms.GetOffset();
        !           239:                roms.Write4(OP_or_u     (r11, r0,  0x4100));
        !           240:                roms.Write4(OP_or       (r11, r11, roms.GetOffset() + 8));
        !           241:                roms.Write4(OP_br       (0));                           // STOP 相当
        !           242:                roms.Write4(OP_or       (r11, r0, r0));
1.1.1.11  root      243: 
1.1.1.14  root      244:        // _entry:
1.1.1.15! root      245:                roms.Write4(OP_ld       (r2, r3, (ROMIO_ENTRY - ROMIO_BASE)));
        !           246:                roms.Write4(OP_or_c     (r5, r0, r0));          // r5 <- $ffffffff
        !           247:                roms.Write4(OP_cmp      (r5, r2, r5));
        !           248:                roms.Write4(OP_bb1      (CMP_EQ, r5, -7));      // 起動先なければループ
1.1.1.8   root      249:        // _go:
                    250:                // 起動先があれば後始末して
1.1.1.15! root      251:                roms.Write4(OP_ld       (r0, r3, (ROMIO_CLOSE - ROMIO_BASE)));
1.1.1.14  root      252:                // 割り込み禁止に戻して
1.1.1.15! root      253:                roms.Write4(OP_stcr     (r10, psr));
1.1.1.14  root      254:                // 戻ってきたときのために r1 を用意して
1.1.1.15! root      255:                roms.Write4(OP_or_u     (r1, r0, 0x4100));
        !           256:                roms.Write4(OP_or       (r1, r1, roms.GetOffset() + 8));
1.1.1.8   root      257:                // ジャンプ
1.1.1.15! root      258:                roms.Write4(OP_jmp      (r2));
1.1.1.14  root      259:                // 戻ってきたら
1.1.1.15! root      260:                roms.Write4(OP_br       ((prompt - roms.GetOffset()) / 4));
1.1.1.5   root      261: 
1.1.1.14  root      262:        // 割り込みハンドラ。
                    263:        // _intr:
1.1.1.15! root      264:        roms.SetOffset(0x200);
        !           265:                roms.Write4(OP_or_u     (r6, r0, 0x6500));
        !           266:                roms.Write4(OP_ld       (r6, r6, 0));
        !           267:                roms.Write4(OP_extu     (r6, r6, 3, 29));
        !           268:                roms.Write4(OP_or       (r7, r0, 6));
        !           269:                roms.Write4(OP_cmp      (r7, r6, r7));
        !           270:                roms.Write4(OP_bb1      (CMP_EQ, r7, (0x240 - roms.GetOffset()) / 4));
1.1.1.14  root      271:        // key_intr:
1.1.1.15! root      272:                roms.Write4(OP_ld       (r0, r3, (ROMIO_KEYIN - ROMIO_BASE)));
1.1.1.14  root      273:        // _intr_ret:
                    274:                // r11 があればそこに戻る
1.1.1.15! root      275:                uint32 intr_ret = roms.GetOffset();
        !           276:                roms.Write4(OP_bcnd     (eq0, r11, 5));         // beq @f
        !           277:                roms.Write4(OP_or       (r6, r11, SxIP_VALID));
        !           278:                roms.Write4(OP_stcr     (r6, snip));
        !           279:                roms.Write4(OP_addu     (r6, r6, 0x0004));
        !           280:                roms.Write4(OP_stcr     (r6, sfip));
1.1.1.14  root      281:        // @@:
1.1.1.15! root      282:                roms.Write4(OP_rte      ());
1.1.1.8   root      283: 
1.1.1.14  root      284:        // Sysclk 割り込みハンドラ。
1.1.1.15! root      285:        roms.SetOffset(0x240);
1.1.1.14  root      286:                // ACK
1.1.1.15! root      287:                roms.Write4(OP_or_u     (r6, r0, 0x6300));
        !           288:                roms.Write4(OP_st_b     (r0, r6, r0));
1.1.1.14  root      289:                // inc
1.1.1.15! root      290:                roms.Write4(OP_ld       (r6, r3, (ROMIO_CLKCNT - ROMIO_BASE)));
        !           291:                roms.Write4(OP_addu     (r6, r6, 1));
        !           292:                roms.Write4(OP_st       (r6, r3, (ROMIO_CLKCNT - ROMIO_BASE)));
        !           293:                roms.Write4(OP_br       ((intr_ret - roms.GetOffset()) / 4));
1.1.1.14  root      294: 
1.1.1.8   root      295:        // ROM GETC エミュレータ
1.1.1.15! root      296:        roms.SetOffset(0x300);
        !           297:                roms.Write4(OP_doscall(r2, r0, DOS_GETCHAR));
        !           298:                roms.Write4(OP_jmp      (r1));
1.1.1.8   root      299: 
                    300:        // ROM PUTC エミュレータ
1.1.1.13  root      301:        // 表示する文字は r2 に置かれている。
1.1.1.15! root      302:        roms.SetOffset(0x400);
        !           303:                roms.Write4(OP_doscall(r0, r2, DOS_PUTCHAR));
        !           304:                roms.Write4(OP_jmp      (r1));
1.1.1.8   root      305: 
1.1.1.14  root      306:        // サブルーチン
1.1.1.15! root      307:        roms.SetOffset(0x900);
        !           308:                roms.Write4(OP_ld       (r2, r3, (ROMIO_AP1 - ROMIO_BASE)));
1.1.1.14  root      309:        //@@:
1.1.1.15! root      310:                roms.Write4(OP_or_u     (r11, r0,  0x4100));
        !           311:                roms.Write4(OP_or       (r11, r11, roms.GetOffset() + 8));
        !           312:                roms.Write4(OP_br       (0));                           // STOP 相当
        !           313:                roms.Write4(OP_or       (r11, r0, r0));
        !           314: 
        !           315:                roms.Write4(OP_ld       (r2, r3, (ROMIO_CLKCNT - ROMIO_BASE)));
        !           316:                roms.Write4(OP_or       (r5, r0, 0x01ff));
        !           317:                roms.Write4(OP_and      (r2, r2, r5));          // r2 &= 0x1ff;
        !           318:                uint freq = sysclk->GetFreq();
        !           319:                roms.Write4(OP_or       (r5, r0, freq * 3));// r5 = freq*3;
        !           320:                roms.Write4(OP_cmp      (r5, r2, r5));
        !           321:                roms.Write4(OP_bb1      (CMP_LT, r5, -9));      // blt @b
        !           322:                roms.Write4(OP_ld       (r0, r3, (ROMIO_AP2 - ROMIO_BASE)));
        !           323:                roms.Write4(OP_jmp      (r1));
1.1.1.8   root      324: 
                    325:        // 変なインデントここまで
1.1       root      326: 
                    327:        return true;
                    328: }
                    329: 
1.1.1.14  root      330: // ROM 起動時の初期化 (機種依存部分) を行う。
                    331: void
                    332: Luna88kPROMEmuDevice::ROM_InitMD()
1.1       root      333: {
1.1.1.15! root      334:        IODeviceStream rams(mainram);
1.1.1.13  root      335: 
1.1.1.14  root      336:        // 割り込みマスクで Sysclk, SIO だけ許可
1.1.1.15! root      337:        // XXX とりあえず CPU#0 のみ
        !           338:        auto *sysctlr = dynamic_cast<SysCtlrDevice*>(GetInterruptDevice());
        !           339:        sysctlr->WriteIntMask(0, 0xc0000000);
1.1       root      340: 
1.1.1.15! root      341:        rams.SetOffset(0);
1.1.1.5   root      342:        // ベクタテーブルを rte で埋めておく
                    343:        for (int i = 0; i < 512 * 2; i++) {
1.1.1.15! root      344:                rams.Write4(OP_rte());
1.1.1.5   root      345:        }
                    346:        // +$08: 割り込みベクタ
1.1.1.15! root      347:        rams.Write4(8, OP_br(0x003fe)); // br   $00001000
1.1.1.5   root      348: 
                    349:        // 割り込みトランポリン (0x1000)
                    350:        // ベクタテーブルは各2ワードしかないのに、0 番地付近にあるベクタテーブル
                    351:        // から2ワードでは ROM まで飛べない。一体どういう設計してんだ…。
1.1.1.15! root      352:        rams.SetOffset(0x1000);
        !           353:                rams.Write4(OP_or_u     (r6, r0, 0x4100));
        !           354:                rams.Write4(OP_or       (r6, r6, 0x0200));
        !           355:                rams.Write4(OP_jmp      (r6));
1.1.1.2   root      356: 
1.1.1.5   root      357:        // ROM の機能テーブル
1.1.1.8   root      358:        // 0x00001100 ?
                    359:        // 0x00001104 ?
                    360:        // 0x00001108 ?
                    361:        // 0x0000110c GETC() のアドレス
                    362:        // 0x00001110 PUTC(c) のアドレス
1.1.1.5   root      363:        // 0x00001114 ビットマッププレーンの有効状態が入っている。
                    364:        //  bit0: plane0 有効
                    365:        //  bit1..7: plane1..7 有効
1.1.1.15! root      366:        rams.SetOffset(0x110c);
        !           367:                rams.Write4(0x41000300);
        !           368:                rams.Write4(0x41000400);
        !           369:                rams.Write4(0x00000001);
1.1.1.5   root      370: 
1.1.1.15! root      371:        uint32 ap = (nvram->PeekPort(0x7fd) << 8) | nvram->PeekPort(0x7fe);
1.1.1.14  root      372:        if (__predict_false(0||(ap & 0x3f1f) == 0x0104)) {
                    373:                auto *mpu88xx0 = GetMPU88xx0Device(mpu);
                    374:                mpu88xx0->reg.r[1] = mpu88xx0->reg.nip;
                    375:                mpu88xx0->DoBranch(0x41000900, false);
                    376:        }
                    377: }
1.1.1.5   root      378: 
1.1.1.14  root      379: // ファイルをロードする。
                    380: // -X が指定されていればそのホストファイル。
                    381: // そうでなければゲストファイル。この場合引数 fname があれば
                    382: // NVRAM で指定されたデバイスから読み込む際のファイル名とする。
                    383: // ロードできればエントリポイントを返す。
                    384: // ロードできなければ errmsg にメッセージをセットし -1 を返す。
                    385: uint32
                    386: Luna88kPROMEmuDevice::LoadFile(const std::string& fname)
                    387: {
                    388:        uint32 entry;
1.1.1.5   root      389: 
1.1.1.10  root      390:        if (gMainApp.exec_file) {
1.1.1.14  root      391:                // -X が指定されてたらホストプログラムを読み込む。
                    392:                entry = LoadHostFile();
1.1.1.10  root      393:        } else {
1.1.1.14  root      394:                // NVRAM で指定されるゲストプログラムを読み込む。
                    395:                // XXX とりあえず boot を起動するだけ
                    396:                bootinfo_t bootinfo;
                    397:                GetNVRAM(bootinfo);
                    398:                // 引数で指定されたらファイル名だけ上書き
                    399:                if (fname.empty() == false) {
                    400:                        bootinfo.dkfile = fname;
1.1.1.5   root      401:                }
1.1.1.14  root      402:                entry = LoadGuestFile(bootinfo);
1.1.1.5   root      403:        }
                    404: 
                    405:        return entry;
                    406: }
                    407: 
1.1.1.7   root      408: void
1.1.1.13  root      409: Luna88kPROMEmuDevice::ProcessChar(char asciicode)
1.1.1.7   root      410: {
                    411:        if (prompt_idx == 0) {
                    412:                // 行入力モード (画面更新もしてある)
1.1.1.13  root      413:                inherited::ProcessChar(asciicode);
1.1.1.7   root      414:        } else {
                    415:                // 0 以外ならノンブロッキングモード
                    416: 
                    417:                // 入力されたキーを表示
                    418:                if (' ' <= asciicode && asciicode < 0x7f) {
1.1.1.11  root      419:                        Putc(asciicode);
1.1.1.7   root      420:                }
                    421: 
                    422:                switch (prompt_idx) {
                    423:                 case PROMPT_NVRAM_UPDATE:
                    424:                        CommandNvramUpdate2(asciicode);
                    425:                        break;
                    426: 
                    427:                 case PROMPT_NVRAM_NEW:
                    428:                        CommandNvramNew2(asciicode);
                    429:                        break;
                    430: 
                    431:                 case PROMPT_NVRAM_INIT:
                    432:                        CommandNvramInit2(asciicode);
                    433:                        break;
                    434:                }
                    435: 
                    436:                // プロンプトを戻す
                    437:                prompt = default_prompt;
                    438:                prompt_idx = 0;
1.1.1.11  root      439:                prompt_y = cursor_y;
                    440:                ClearPrompt();
1.1.1.7   root      441:        }
                    442: }
                    443: 
1.1.1.5   root      444: // 入力コマンド処理 (入力行が揃ったところで呼ばれる)。
                    445: //
                    446: // b                                   現在のパラメータで起動
                    447: // b ...                               パラメータを指定して起動
                    448: // nvram                               全パラメータを表示
                    449: // nvram [<name>]              name のみ表示?
                    450: // nvram <name> <val>  値を設定
                    451: // nvram - <name>              削除
                    452: // nvram--                             NVRAM 初期化
                    453: 
                    454: void
                    455: Luna88kPROMEmuDevice::Command()
1.1.1.2   root      456: {
1.1.1.5   root      457:        std::vector<char> buf(inputbuf.length() + 1);
                    458:        std::vector<std::string> arg;
1.1.1.2   root      459: 
1.1.1.5   root      460:        // 1ワードごとに分解
1.1.1.15! root      461:        strlcpy(buf.data(), inputbuf.c_str(), buf.size());
1.1.1.5   root      462:        char *p = &buf[0];
1.1.1.6   root      463:        for (char *ap; (ap = strsep(&p, " ")) != NULL; ) {
                    464:                if (*ap != '\0') {
                    465:                        arg.push_back(std::string(ap));
1.1.1.5   root      466:                }
                    467:        }
                    468:        if (loglevel >= 1) {
                    469:                for (int i = 0; i < arg.size(); i++) {
1.1.1.15! root      470:                        putmsgn("arg[%u]=|%s|", i, arg[i].c_str());
1.1.1.5   root      471:                }
                    472:        }
1.1.1.2   root      473: 
1.1.1.5   root      474:        // 空行
                    475:        if (arg.size() == 0) {
                    476:                return;
                    477:        }
                    478: 
                    479:        // 1ワード目がコマンド
                    480:        if (arg[0] == "h") {
1.1.1.7   root      481:                CommandH(arg);
1.1.1.5   root      482:                return;
                    483:        }
                    484:        if (arg[0] == "b") {
                    485:                CommandB(arg);
                    486:                return;
                    487:        }
                    488:        if (arg[0] == "nvram") {
                    489:                CommandNvram(arg);
                    490:                return;
1.1.1.2   root      491:        }
1.1.1.5   root      492: 
1.1.1.11  root      493:        Print("** Unknown command: %s\n", arg[0].c_str());
1.1.1.2   root      494: }
                    495: 
1.1.1.7   root      496: // "h" コマンド
                    497: // 引数なしなら、全体のヘルプメッセージ。
                    498: // 引数ありなら、個別のヘルプメッセージ。
                    499: void
                    500: Luna88kPROMEmuDevice::CommandH(const std::vector<std::string>& arg)
                    501: {
                    502:        if (arg.size() < 2) {
                    503:                // ヘルプメッセージ
                    504:  mainhelp:
1.1.1.11  root      505:                Print(
1.1.1.7   root      506: "         *** Help Message ***\n"
                    507: "  b      : load and execute program\n"
                    508: "  h      : show this message\n"
                    509: "  nvram  : show/set nvram parameters\n"
                    510:                );
                    511:                return;
                    512:        }
                    513: 
                    514:        const std::string& key = arg[1];
                    515:        if (key == "nvram") {
1.1.1.11  root      516:                Print(
1.1.1.7   root      517: "         *** Help Message ***\n"
                    518: " nvram [<symbol>]       : show\n"
                    519: " nvram <symbol> <value> : set\n"
                    520: " nvram - <symbol>       : delete\n"
                    521: " nvram --               : initialize\n"
                    522:                );
                    523:                return;
                    524:        } else {
                    525:                goto mainhelp;
                    526:        }
                    527: }
                    528: 
1.1.1.5   root      529: // "b" コマンド
1.1.1.14  root      530: // 引数なしなら NVRAM の情報 (もしくは -X オプション) に従ってプログラムを
                    531: // ロードして実行。引数ありのほうは未実装。
1.1.1.5   root      532: void
                    533: Luna88kPROMEmuDevice::CommandB(const std::vector<std::string>& arg)
1.1       root      534: {
1.1.1.14  root      535:        entrypoint = LoadFile("");
                    536:        if (entrypoint == -1) {
1.1.1.11  root      537:                Print("** %s\n", errmsg.c_str());
1.1.1.14  root      538:        } else {
                    539:                execute = true;
                    540:                Print("%s.  Entry point = $%08x\n",
                    541:                        (gMainApp.exec_file ? "Host program loaded" : "Loaded"),
                    542:                        entrypoint);
1.1       root      543:        }
1.1.1.5   root      544: }
1.1       root      545: 
1.1.1.7   root      546: // "nvram" コマンド
                    547: // nvram             .. 全表示
                    548: // nvram <key>       .. 表示
                    549: // nvram <key> <val> .. 追加/更新
                    550: // nvram - <key>     .. 削除
                    551: // nvram --          .. 初期化
1.1.1.5   root      552: void
                    553: Luna88kPROMEmuDevice::CommandNvram(const std::vector<std::string>& arg)
1.1.1.2   root      554: {
1.1.1.7   root      555:        switch (arg.size()) {
                    556:         case 1:
                    557:                // 引数なし
                    558:                CommandNvramShowAll();
                    559:                break;
                    560:         case 2:
                    561:                // 引数1つ
                    562:                if (arg[1] == "--") {
                    563:                        CommandNvramInit();
                    564:                } else {
                    565:                        CommandNvramShow(arg);
                    566:                }
                    567:                break;
                    568:         case 3:
                    569:                // 引数2つ
                    570:                if (arg[1] == "-") {
                    571:                        CommandNvramDelete(arg);
                    572:                } else {
                    573:                        CommandNvramUpdate(arg);
                    574:                }
                    575:                break;
                    576:         default:
1.1.1.11  root      577:                Print("** Syntax error\n");
1.1.1.7   root      578:        }
                    579: }
                    580: 
                    581: // NVRAM は 32バイトを1エントリとする。
                    582: // [0] はヘッダに相当し、フォーマットは別記。
                    583: // [1] 以降が key (16バイト)、val(16バイト) の並び。こんな感じ。
                    584: //
                    585: // 00000020  62 6f 6f 74 5f 64 65 76 69 63 65 00 00 00 00 00 |boot_device.....|
                    586: // 00000030  73 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |sd..............|
                    587: //
                    588: // key, val とも '\0' で終端もしくは16文字で終端のようだ。
                    589: // val に17文字を設定しようとすると怒られる。
                    590: // key が "" ならこのエントリは空きで val は無視、
                    591: // 空きエントリは無視して次へ (FAT のディレクトリエントリみたいな感じ)。
                    592: // val が "" は有効。
                    593: //
                    594: // オフセット 0x540 から始まるエントリが最後で、これ以上追加しようとすると
                    595: // "nvram set error: no area" (PROM 1.20) と言われる。
1.1.1.13  root      596: // LUNA-88K にはないが LUNA-I では 0x560 にぽつんと ENADDR があったので、
1.1.1.7   root      597: // その辺りとの互換性だろうか。
                    598: 
                    599: // NVRAM 全項目表示
                    600: void
                    601: Luna88kPROMEmuDevice::CommandNvramShowAll()
                    602: {
                    603:        putmsg(1, "nvram ShowAll");
                    604:        for (uint32 offset = 0x20; offset < 0x560; offset += 0x20) {
                    605:                std::string key = nvram->PeekString(offset);
                    606:                if (key.empty()) {
                    607:                        continue;
                    608:                }
                    609:                std::string val = nvram->PeekString(offset + 16);
1.1.1.11  root      610:                Print("%-15s : %s\n", key.c_str(), val.c_str());
1.1.1.7   root      611:        }
                    612: }
                    613: 
                    614: // NVRAM 指定項目を表示
                    615: void
                    616: Luna88kPROMEmuDevice::CommandNvramShow(const std::vector<std::string>& arg)
                    617: {
                    618:        assert(arg.size() >= 2);
                    619:        const std::string& key = arg[1];
                    620: 
                    621:        putmsg(1, "nvram Show |%s|", key.c_str());
                    622:        uint32 offset = FindNVRAM(key);
                    623:        if (offset > 0) {
                    624:                std::string val = nvram->PeekString(offset + 16);
1.1.1.11  root      625:                Print("%-15s : %s\n", key.c_str(), val.c_str());
1.1.1.7   root      626:        } else {
1.1.1.11  root      627:                Print("** Not found\n");
1.1.1.7   root      628:        }
                    629: }
                    630: 
                    631: // NVRAM 項目を追加/更新
                    632: void
                    633: Luna88kPROMEmuDevice::CommandNvramUpdate(const std::vector<std::string>& arg)
                    634: {
                    635:        // キーがあれば更新、なければ追加。
                    636:        // いずれも事前にプロンプトで確認する。
                    637: 
                    638:        assert(arg.size() >= 3);
                    639:        nvram_key = arg[1];
                    640:        nvram_val = arg[2];
                    641:        putmsg(1, "nvram Update |%s|%s|", nvram_key.c_str(), nvram_val.c_str());
                    642: 
                    643:        if (nvram_key.size() > 16) {
1.1.1.11  root      644:                Print("** Key too long\n");
1.1.1.7   root      645:                return;
                    646:        }
                    647:        if (nvram_val.size() > 16) {
1.1.1.11  root      648:                Print("** Val too long\n");
1.1.1.7   root      649:                return;
                    650:        }
                    651: 
                    652:        nvram_offset = FindNVRAM(nvram_key);
                    653:        if (nvram_offset > 0) {
                    654:                // キーがすでにあれば更新。
                    655:                // Update2() に申し送りするのは nvram_offset と nvram_val のみでいい。
                    656: 
                    657:                std::string oldval = nvram->PeekString(nvram_offset + 16);
                    658:                prompt = string_format("Update %s : \"%s\" -> \"%s\" (Y/[N]):",
                    659:                        nvram_key.c_str(), oldval.c_str(), nvram_val.c_str());
                    660:                prompt_idx = PROMPT_NVRAM_UPDATE;
                    661:        } else {
                    662:                // キーがなければ追加
                    663:                // New2() に申し送りするのは nvram_offset, nvram_key, nvram_val の3つ。
                    664: 
                    665:                // 先に空き領域をチェックしている
                    666:                nvram_offset = FindNVRAM("");
                    667:                if (nvram_offset == 0) {
1.1.1.11  root      668:                        Print("** No area available\n");
1.1.1.7   root      669:                        return;
                    670:                }
                    671: 
                    672:                prompt = string_format("Set new %s : \"%s\" (Y/[N]):",
                    673:                        nvram_key.c_str(), nvram_val.c_str());
                    674:                prompt_idx = PROMPT_NVRAM_NEW;
                    675:        }
                    676: 
                    677:        // 入力待ちの状態で戻る
                    678:        // (prompt_idx != 0 なのでキー入力後に指定の関数へ飛んで続きを実行する)
                    679: }
                    680: 
                    681: // NVRAM 項目を更新 (キー入力後)
                    682: void
                    683: Luna88kPROMEmuDevice::CommandNvramUpdate2(char asciicode)
                    684: {
                    685:        assert(prompt_idx == PROMPT_NVRAM_UPDATE);
                    686:        assert(nvram_offset > 0);
                    687:        assert(nvram_val.size() <= 16);
                    688: 
1.1.1.11  root      689:        Putc('\n');
1.1.1.7   root      690: 
                    691:        if (asciicode != 'y' && asciicode != 'Y') {
1.1.1.11  root      692:                Print("** Not updated\n");
1.1.1.7   root      693:                return;
                    694:        }
                    695: 
                    696:        if (nvram->WriteString(nvram_offset + 16, nvram_val) == false) {
1.1.1.11  root      697:                Print("** Write error\n");
1.1.1.7   root      698:                return;
                    699:        }
                    700:        WriteNVRAMCsum();
                    701: 
1.1.1.11  root      702:        Print("Updated\n");
1.1.1.7   root      703: }
                    704: 
                    705: // NVRAM 項目を追加 (キー入力後)
                    706: void
                    707: Luna88kPROMEmuDevice::CommandNvramNew2(char asciicode)
                    708: {
                    709:        assert(prompt_idx == PROMPT_NVRAM_NEW);
                    710:        assert(nvram_offset > 0);
                    711:        assert(!nvram_key.empty());
                    712:        assert(nvram_key.size() <= 16);
                    713:        assert(nvram_val.size() <= 16);
                    714: 
1.1.1.11  root      715:        Putc('\n');
1.1.1.7   root      716: 
                    717:        if (asciicode != 'y' && asciicode != 'Y') {
1.1.1.11  root      718:                Print("** Not added\n");
1.1.1.7   root      719:                return;
                    720:        }
                    721: 
                    722:        if (nvram->WriteString(nvram_offset, nvram_key) == false
                    723:         || nvram->WriteString(nvram_offset + 16, nvram_val) == false) {
1.1.1.11  root      724:                Print("** Write error\n");
1.1.1.7   root      725:                return;
                    726:        }
                    727:        WriteNVRAMCsum();
                    728: 
1.1.1.11  root      729:        Print("Added\n");
1.1.1.2   root      730: }
                    731: 
1.1.1.7   root      732: // NVRAM 項目削除
                    733: //
                    734: // 削除する時は確認がないらしい… (PROM 1.20)
                    735: // 成功しても何も言わないらしい… (PROM 1.20)
                    736: // 追加削除に比べてなんか雑じゃない?
                    737: void
                    738: Luna88kPROMEmuDevice::CommandNvramDelete(const std::vector<std::string>& arg)
                    739: {
                    740:        assert(arg.size() >= 3);
                    741:        assert(arg[1] == "-");
                    742:        const std::string& key = arg[2];
                    743:        putmsg(1, "nvram Delete |%s|", key.c_str());
                    744: 
                    745:        if (key.size() > 16) {
1.1.1.11  root      746:                Print("** key too long\n");
1.1.1.7   root      747:                return;
                    748:        }
                    749: 
                    750:        uint32 offset = FindNVRAM(key);
                    751:        if (offset == 0) {
1.1.1.11  root      752:                Print("** Not found\n");
1.1.1.7   root      753:                return;
                    754:        }
                    755: 
                    756:        // キーを消せば削除になる (値のほうは消してないようだ)
                    757:        nvram->WriteString(offset, "");
                    758:        WriteNVRAMCsum();
                    759: }
                    760: 
                    761: // NVRAM から key を探してそのエントリのオフセットを返す。
                    762: // key == "" なら空きエントリを探す。
                    763: // 見付からなければ 0 を返す (オフセット 0 はパラメータには使わないため)
                    764: uint32
                    765: Luna88kPROMEmuDevice::FindNVRAM(const std::string& key) const
1.1.1.2   root      766: {
1.1.1.7   root      767:        for (uint32 offset = 0x20; offset < 0x560; offset += 0x20) {
                    768:                std::string k = nvram->PeekString(offset);
                    769:                if (k == key) {
                    770:                        return offset;
                    771:                }
                    772:                // XXX 同じキーが複数あったらどうなるか
                    773:        }
1.1.1.2   root      774:        return 0;
                    775: }
                    776: 
1.1.1.7   root      777: // NVRAM 初期化
1.1.1.5   root      778: void
1.1.1.7   root      779: Luna88kPROMEmuDevice::CommandNvramInit()
1.1.1.2   root      780: {
1.1.1.7   root      781:        putmsg(1, "nvram Init");
                    782: 
                    783:        prompt = "Initialize (Y/[N]):";
                    784:        prompt_idx = PROMPT_NVRAM_INIT;
                    785: 
                    786:        // 入力待ちの状態で戻る
1.1.1.2   root      787: }
                    788: 
1.1.1.7   root      789: // NVRAM 初期化 (キー入力後)
                    790: void
                    791: Luna88kPROMEmuDevice::CommandNvramInit2(char asciicode)
1.1.1.2   root      792: {
1.1.1.7   root      793:        assert(prompt_idx == PROMPT_NVRAM_INIT);
                    794: 
1.1.1.11  root      795:        Putc('\n');
1.1.1.7   root      796: 
                    797:        if (asciicode != 'y' && asciicode != 'Y') {
1.1.1.11  root      798:                Print("** Not initialized\n");
1.1.1.7   root      799:                return;
                    800:        }
                    801: 
                    802:        InitNVRAM();
1.1.1.11  root      803:        Print("** Initialized\n");
1.1       root      804: }
                    805: 
1.1.1.5   root      806: // NVRAM を初期化する
                    807: bool
                    808: Luna88kPROMEmuDevice::InitNVRAM()
1.1       root      809: {
1.1.1.7   root      810:        nvram->ClearAll();
                    811: 
                    812:        nvram->WriteString(0x0004, "<nv>");
                    813:        nvram->WriteString(0x0020, "boot_device");
                    814:        nvram->WriteString(0x0030, "sd");
                    815:        nvram->WriteString(0x0040, "boot_spec");
                    816:        nvram->WriteString(0x0050, "0");
                    817:        nvram->WriteString(0x0060, "boot_unit");
                    818:        nvram->WriteString(0x0070, "0");
                    819:        nvram->WriteString(0x0080, "boot_partition");
                    820:        nvram->WriteString(0x0090, "0");
                    821:        nvram->WriteString(0x00a0, "boot_filename");
                    822:        nvram->WriteString(0x00b0, "vmunix");
                    823:        nvram->WriteString(0x00c0, "main_mem_check");
                    824:        nvram->WriteString(0x00d0, "1");
                    825:        nvram->WriteString(0x00e0, "3port_mem_check");
                    826:        nvram->WriteString(0x00f0, "1");
                    827: 
                    828:        // チェックサム再計算
                    829:        WriteNVRAMCsum();
                    830: 
                    831:        return true;
1.1.1.5   root      832: }
1.1       root      833: 
1.1.1.5   root      834: // NVRAM のブート設定を bootinfo に取得する。
                    835: void
                    836: Luna88kPROMEmuDevice::GetNVRAM(bootinfo_t& bootinfo)
                    837: {
1.1.1.7   root      838:        // dkunit (装置番号) はたぶん boot_unit (0..)
                    839:        // dkpart (パーティション) は boot_partition (0..)
                    840:        // dkfile (ファイル名) は boot_filename
                    841:        // sd 以外のデバイスは未対応
1.1.1.15! root      842:        bootinfo.dkunit = nvram->PeekPort(0x0070) - '0';
        !           843:        bootinfo.dkpart = nvram->PeekPort(0x0090) - '0';
1.1.1.7   root      844:        bootinfo.dkfile = nvram->PeekString(0x00b0);
1.1.1.15! root      845:        putmsg(1, "%s unit=%u", __func__, bootinfo.dkunit);
1.1.1.7   root      846:        putmsg(1, "%s part=%c", __func__, bootinfo.dkpart + 'a');
                    847:        putmsg(1, "%s file=|%s|", __func__, bootinfo.dkfile.c_str());
1.1       root      848: }
1.1.1.8   root      849: 
                    850: // コールバック関数 (C のグローバル関数)
                    851: bool
1.1.1.13  root      852: luna88k_fline_callback(MPU88xx0Device *cpu, void *arg)
1.1.1.8   root      853: {
1.1.1.15! root      854:        auto *dev = reinterpret_cast<Luna88kPROMEmuDevice *>(arg);
1.1.1.8   root      855:        return dev->FLineCallback(cpu);
                    856: }
                    857: 
                    858: // コールバック関数 (こっちが実体)
                    859: bool
1.1.1.13  root      860: Luna88kPROMEmuDevice::FLineCallback(MPU88xx0Device *cpu)
1.1.1.8   root      861: {
                    862:        // 111111_DDDDDSSSSS_000001_00nnnnnnnn
                    863:        //
                    864:        // 引数は rS1 から順番に格納。
                    865:        // m68k 的なバイト値やワード値の場合は下位詰めしてあるが、不要な上位
                    866:        // ビットの処置はゲストコードよりホストコードで行うほうが楽なので、
                    867:        // すべてこちらで責任持って処理すること。
                    868:        // 戻り値がある DOS call では戻り値は rD に格納。
                    869: 
1.1.1.13  root      870:        uint32 D   = (cpu->reg.opX >> 21) & 0x1f;
                    871:        uint32 S1  = (cpu->reg.opX >> 16) & 0x1f;
                    872:        uint32 num =  cpu->reg.opX        & 0xff;
1.1.1.8   root      873: 
                    874:        switch (num) {
                    875:         case 0x00:     // _EXIT
                    876:                break;
                    877: 
                    878:         case 0x01:     // _GETCHAR
1.1.1.13  root      879:                cpu->reg.r[D] = Getc();
1.1.1.8   root      880:                break;
                    881: 
                    882:         case 0x02:     // _PUTCHAR
1.1.1.13  root      883:                Putc(cpu->reg.r[S1++] & 0xff);
1.1.1.8   root      884:                break;
                    885: 
                    886:         default:
1.1.1.12  root      887:                putlog(0, "DOS call #$%02x (NOT IMPLEMENTED)", num);
1.1.1.13  root      888:                cpu->reg.r[D] = 0xffffffff;
1.1.1.8   root      889:                break;
                    890:        }
                    891: 
                    892:        // 存在しないコール番号、未実装コールも含めて処理済みとする。
                    893:        return true;
                    894: }

unix.superglobalmegacorp.com

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