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

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

unix.superglobalmegacorp.com

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