Annotation of nono/hd64180/hd64180core.cpp, revision 1.1.1.3

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2022 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // HD647180 コア
                      9: //
                     10: 
                     11: #include "mpu64180.h"
                     12: #include "debugger.h"
                     13: #include "hd64180.h"
                     14: #include "hd647180.h"
                     15: #include "scheduler.h"
                     16: 
                     17: #define OP_DEF(name)   void __CONCAT(MPU64180Device::op_,name)()
                     18: #define OP_FUNC(name)  __CONCAT(op_,name)()
                     19: #include "hd64180ops.cpp"
                     20: 
                     21: void
                     22: MPU64180Device::ExecNormal(Event& ev)
                     23: {
                     24:        uint64 cycle_start = used_cycle;
                     25: 
                     26:        ppc = reg.pc;
                     27:        ixiy = USE_HL;
                     28:        ixd = -1;
                     29:        ops.clear();
                     30:        intcheck = true;
                     31: 
                     32:        // R レジスタは命令ごとにカウント。7bit マスクは読み出し時に行う。
                     33:        // 命令の前か後かは分からないが。
                     34:        reg_r++;
                     35: 
                     36:        // 1バイト目処理
1.1.1.2   root       37:        op = Fetch1();
1.1       root       38:        if (__predict_false(opmode == OpMode::Halt)) {
                     39:                // ホールトモードなら PC を戻し続けるだけ
                     40:                reg.pc--;
                     41:                CYCLE(3);
                     42:        } else {
                     43:                switch (op) {
                     44: #include "hd64180switch_00.inc"
                     45:                 default:
                     46:                        __unreachable();
                     47:                }
                     48:        }
                     49: 
                     50:        // 割り込みチェック。
                     51:        if (__predict_true(intcheck)) {
                     52:                // intmap が非ゼロなら割り込み発生中。
                     53:                if (GetIEF1() == true && __predict_false(intmap != 0)) {
                     54:                        DoInterrupt();
                     55:                }
                     56:        } else {
                     57:                // この命令境界での割り込みチェックを飛ばす。次からは行う。
                     58:                intcheck = true;
                     59:        }
                     60: 
                     61:        int cycle = used_cycle - cycle_start;
                     62:        ev.time = cycle * clock_nsec;
                     63:        scheduler->StartEvent(ev);
                     64: }
                     65: 
                     66: // 不当命令。
                     67: // pos は不当命令になったバイト位置。2バイト目なら2。
                     68: void
                     69: MPU64180Device::op_illegal(int pos)
                     70: {
                     71:        // ログ表示
                     72:        std::string str;
                     73:        for (auto o : ops) {
                     74:                str += string_format(" %02x", o);
                     75:        }
                     76:        putlog(1, "Undefined opcode%s", str.c_str());
                     77: 
                     78:        itc_trap = true;
                     79:        // 3バイト目なら UFO ビットをセット。
                     80:        itc_ufo = (pos == 3);
                     81: 
                     82:        // XXX CYCLE
                     83: 
                     84:        // TRAP 割り込みはマスク不可能。
                     85:        // IEF[12] not affected
                     86: 
                     87:        // (1) ITC の TRAP ビットを 1 にする
                     88:        // (2) 未定義 opcode 位置の PC をスタックに保存する
                     89:        // (3) ベクタを 0000H にする
                     90: 
                     91:        // PC は未定義命令の先頭番地ではなく、未定義 opcode だった位置?
                     92:        // nono の実装ではフェッチと同時にインクリメントしているので、
                     93:        // 1つ前でいい? HD64180.pdf p38-39
1.1.1.3 ! root       94:        if (pos == 2) {
        !            95:                Push2(reg.pc - 1);
        !            96:        } else {
        !            97:                // DD CB d OP xx
        !            98:                //            ^ PC
        !            99:                // d の位置をスタックに積む
        !           100:                Push2(reg.pc - 2);
        !           101:        }
1.1       root      102:        ExceptionDirect(HD647180::IntmapTRAP, 0x0000);
                    103: }
                    104: 
                    105: // 分岐
                    106: void
                    107: MPU64180Device::Jump(uint16 addr)
                    108: {
                    109:        reg.pc = addr;
                    110: 
                    111:        // 命令本体(オペランドを含まない)を16ビット左詰めにする。
                    112:        // 分岐命令は1バイト命令か ED XX か DD/FD XX の2バイト命令しかないはず。
                    113:        //上位ワードは $0000。
                    114:        uint32 inst;
                    115:        if (ops[0] == 0xed || ops[0] == 0xdd || ops[0] == 0xfd) {
                    116:                inst = (ops[0] << 8) | ops[1];
                    117:        } else {
                    118:                inst = (ops[0] << 8);
                    119:        }
                    120: 
                    121:        brhist.AddEntry(GetPPC(), addr, inst);
                    122: }
                    123: 
                    124: //
                    125: // 割り込み。
                    126: //
                    127: // TRAP         0000H
                    128: // NMI          0066H
                    129: // INT0 mode0   命令をデータバスからフェッチ
                    130: // INT0 mode1   0038H
                    131: // INT0 mode2   Vectored (上位8bit が I レジスタ、下位8bit はデータバス)
                    132: // INT1         Vectored (I + IL + 固定コード)
                    133: // INT2         Vectored (〃)
                    134: // 内蔵割り込み Vectored (〃)
                    135: 
                    136: // 内部の割り込みマップ (Intmap) をアサートする。
                    137: void
                    138: MPU64180Device::AssertIntmap(int source)
                    139: {
                    140:        uint32 oldmap;
                    141:        uint32 srcmap;
                    142: 
                    143:        oldmap = intmap;
                    144:        srcmap = 1U << (31 - source);
                    145:        intmap |= srcmap;
                    146: 
                    147:        if ((oldmap ^ intmap) != 0) {
                    148:                // 立ち上がりエッジでカウント
                    149:                int_counter[source]++;
                    150: 
                    151:                // ホールトモード、スリープモードなら解除
                    152:                if (__predict_false((int)opmode >= (int)OpMode::Halt)) {
                    153:                        if (opmode == OpMode::Halt) {
                    154:                                // ホールトモードなら解除するだけ。
                    155:                                // XXX 割り込みは一つ次の命令境界で処理されるけど、いいか?
                    156:                                opmode = OpMode::Normal;
                    157:                        } else {
                    158:                                // スリープモードなら通常モードに戻す。
                    159:                                EnterWakeup();
                    160:                        }
                    161:                }
                    162:        }
                    163: }
                    164: 
                    165: // 内部の割り込みマップ (Intmap) をネゲートする。
                    166: void
                    167: MPU64180Device::NegateIntmap(int source)
                    168: {
                    169:        uint32 oldmap;
                    170:        uint32 srcmap;
                    171: 
                    172:        oldmap = intmap;
                    173:        srcmap = 1U << (31 - source);
                    174:        intmap &= ~srcmap;
                    175: 
                    176:        if ((oldmap ^ intmap) != 0) {
                    177:                // 今は立ち下がりで何もすることはない。
                    178:        }
                    179: }
                    180: 
                    181: // INT0 信号線をアサートする。(PIO1 から呼ばれる)
                    182: void
                    183: MPU64180Device::AssertINT0()
                    184: {
                    185:        AssertIntmap(HD647180::IntmapINT0);
                    186: }
                    187: 
                    188: // INT0 信号線をネゲートする。
                    189: void
                    190: MPU64180Device::NegateINT0()
                    191: {
                    192:        NegateIntmap(HD647180::IntmapINT0);
                    193: }
                    194: 
                    195: // マスカブル割り込みを処理する。(命令境界で呼ばれる)
                    196: void
                    197: MPU64180Device::DoInterrupt()
                    198: {
                    199:        // まず割り込み禁止。
                    200:        ief1 = false;
                    201:        ief2 = false;
                    202: 
                    203:        // 優先順位の最も高い割り込みを一つ選択。
                    204:        assert(intmap != 0);
1.1.1.2   root      205:        uint source = __builtin_clz(intmap);
1.1       root      206: 
                    207:        // TRAP はここに来ない。NMI は LUNA では未接続のため未実装。
                    208:        assert(source != HD647180::IntmapTRAP);
                    209:        assert(source != HD647180::IntmapNMI);
                    210: 
                    211:        if (source == HD647180::IntmapINT0) {
                    212:                // INT0 はモードによって分岐方法が異なる。
                    213: 
                    214:                // ただし mode0 と mode2 は使われてないので未対応。
                    215:                if (int0mode != 1) {
1.1.1.2   root      216:                        PANIC("INT0 on mode%u (NOT IMPLEMENTED)", int0mode);
1.1       root      217:                }
                    218: 
                    219:                // mode1 は固定番地へ
1.1.1.2   root      220:                Push2(reg.pc);
1.1       root      221:                ExceptionDirect(source, 0x0038);
                    222:        } else {
                    223:                // 残りはすべてベクタ方式。
                    224: 
1.1.1.2   root      225:                Push2(reg.pc);
1.1       root      226:                ExceptionVector(source);
                    227:        }
                    228: 
                    229:        // XXX あとで見る
                    230:        // HD64180.pdf, p45. Figure 2.7.7
                    231:        CYCLE(11);
                    232: }
                    233: 
                    234: // 例外によって new_addr に直接ジャンプする。
                    235: // (HD64180 系の用語では例外ではなくて割り込みだが)
                    236: // source は Intmap*。
                    237: void
                    238: MPU64180Device::ExceptionDirect(int source, uint32 new_addr)
                    239: {
                    240:        // 例外発生とジャンプを記録。
                    241:        brhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source);
                    242:        exhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source);
                    243: 
                    244:        reg.pc = new_addr;
                    245: 
                    246:        debugger->NotifyExceptionXP(source);
                    247: }
                    248: 
                    249: // 例外ごとに固有のベクタにジャンプする。
                    250: // (HD64180 系の用語では例外ではなくて割り込みだが)
                    251: // source は Intmap*。
                    252: void
                    253: MPU64180Device::ExceptionVector(int source)
                    254: {
                    255:        // 固定コード
                    256:        static uint16 vector_offset[] = {
                    257:                0,              // 0:TRAP
                    258:                0,              // 1:NMI
                    259:                0,              // 2:INT0
                    260: 
                    261:                0x00,   // 3:INT1
                    262:                0x02,   // 4:INT2
                    263:                0x12,   // 5:Input Capture
                    264:                0x14,   // 6:Output Compare
                    265:                0x16,   // 7:Timer Overflow
                    266:                0x04,   // 8:Timer0 (PRT0)
                    267:                0x06,   // 9:Timer1 (PRT1)
                    268:                0x08,   // 10:DMA0
                    269:                0x0a,   // 11:DMA1
                    270:                0x0c,   // 12:CSIO
                    271:                0x0e,   // 13:ASCI0
                    272:                0x10,   // 14:ASCI1
                    273:        };
                    274: 
                    275:        // 例外からベクタアドレスを求める。ベクタアドレスは以下の構成。
                    276:        //
                    277:        //   F  E  D  C  B  A  9  8  7  6  5  4  3  2  1  0
                    278:        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
                    279:        // |      I レジスタ       |  IL    |  固定コード  |
                    280:        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
                    281:        assert(source < countof(vector_offset));
                    282:        uint32 vec_addr = (reg_i << 8) | intvec_low | vector_offset[source];
                    283: 
                    284:        // 例外発生を記録。
                    285:        brhist.AddEntry(GetPPC(), -1, 0x80000000 | source);
                    286:        exhist.AddEntry(GetPPC(), -1, 0x80000000 | source);
                    287: 
                    288:        // ジャンプ先を読み込む
1.1.1.2   root      289:        uint32 new_addr = Read2(vec_addr);
1.1       root      290: 
                    291:        // ベクタジャンプを記録。
                    292:        brhist.AddEntry(vec_addr, new_addr, -1);
                    293: 
                    294:        reg.pc = new_addr;
                    295: 
                    296:        debugger->NotifyExceptionXP(source);
                    297: }
                    298: 
                    299: 
                    300: //
                    301: // hd64180flag
                    302: //
                    303: 
                    304: // F レジスタの値を取得する
                    305: uint8
                    306: hd64180flag::Get() const
                    307: {
                    308:        uint8 f = 0;
                    309: 
                    310:        if (IsS())      f |= HD64180::FlagS;
                    311:        if (IsZ())      f |= HD64180::FlagZ;
                    312:        if (b5)         f |= 0x20;
                    313:        if (IsH())      f |= HD64180::FlagH;
                    314:        if (b3)         f |= 0x08;
                    315:        if (IsPV())     f |= HD64180::FlagPV;
                    316:        if (IsN())      f |= HD64180::FlagN;
                    317:        if (IsC())      f |= HD64180::FlagC;
                    318: 
                    319:        return f;
                    320: }
                    321: 
                    322: // F レジスタに代入する
                    323: void
                    324: hd64180flag::Set(uint8 val)
                    325: {
                    326:        SetS(val & HD64180::FlagS);
                    327:        SetZ(val & HD64180::FlagZ);
                    328:        b5 = (val & 0x20);
                    329:        SetH(val & HD64180::FlagH);
                    330:        b3 = (val & 0x08);
                    331:        SetPV(val & HD64180::FlagPV);
                    332:        SetN(val & HD64180::FlagN);
                    333:        SetC(val & HD64180::FlagC);
                    334: }
                    335: 
                    336: // fff (0..7) の条件が成立すれば true を返す。
                    337: bool
                    338: hd64180flag::IsCond(uint fff) const
                    339: {
                    340:        switch (fff) {
                    341:         case 0:        return !IsZ();  // NZ
                    342:         case 1:        return IsZ();   // Z
                    343:         case 2:        return !IsC();  // NC
                    344:         case 3:        return IsC();   // C
                    345:         case 4:        return !IsPV(); // PO
                    346:         case 5:        return IsPV();  // PE
                    347:         case 6:        return !IsS();  // P
                    348:         case 7:        return IsS();   // M
                    349:         default:
                    350:                PANIC("invalid cond = %u", fff);
                    351:        }
                    352: }

unix.superglobalmegacorp.com

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