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

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.2 ! root       94:        Push2(reg.pc - 1);
1.1       root       95:        ExceptionDirect(HD647180::IntmapTRAP, 0x0000);
                     96: }
                     97: 
                     98: // 分岐
                     99: void
                    100: MPU64180Device::Jump(uint16 addr)
                    101: {
                    102:        reg.pc = addr;
                    103: 
                    104:        // 命令本体(オペランドを含まない)を16ビット左詰めにする。
                    105:        // 分岐命令は1バイト命令か ED XX か DD/FD XX の2バイト命令しかないはず。
                    106:        //上位ワードは $0000。
                    107:        uint32 inst;
                    108:        if (ops[0] == 0xed || ops[0] == 0xdd || ops[0] == 0xfd) {
                    109:                inst = (ops[0] << 8) | ops[1];
                    110:        } else {
                    111:                inst = (ops[0] << 8);
                    112:        }
                    113: 
                    114:        brhist.AddEntry(GetPPC(), addr, inst);
                    115: }
                    116: 
                    117: //
                    118: // 割り込み。
                    119: //
                    120: // TRAP         0000H
                    121: // NMI          0066H
                    122: // INT0 mode0   命令をデータバスからフェッチ
                    123: // INT0 mode1   0038H
                    124: // INT0 mode2   Vectored (上位8bit が I レジスタ、下位8bit はデータバス)
                    125: // INT1         Vectored (I + IL + 固定コード)
                    126: // INT2         Vectored (〃)
                    127: // 内蔵割り込み Vectored (〃)
                    128: 
                    129: // 内部の割り込みマップ (Intmap) をアサートする。
                    130: void
                    131: MPU64180Device::AssertIntmap(int source)
                    132: {
                    133:        uint32 oldmap;
                    134:        uint32 srcmap;
                    135: 
                    136:        oldmap = intmap;
                    137:        srcmap = 1U << (31 - source);
                    138:        intmap |= srcmap;
                    139: 
                    140:        if ((oldmap ^ intmap) != 0) {
                    141:                // 立ち上がりエッジでカウント
                    142:                int_counter[source]++;
                    143: 
                    144:                // ホールトモード、スリープモードなら解除
                    145:                if (__predict_false((int)opmode >= (int)OpMode::Halt)) {
                    146:                        if (opmode == OpMode::Halt) {
                    147:                                // ホールトモードなら解除するだけ。
                    148:                                // XXX 割り込みは一つ次の命令境界で処理されるけど、いいか?
                    149:                                opmode = OpMode::Normal;
                    150:                        } else {
                    151:                                // スリープモードなら通常モードに戻す。
                    152:                                EnterWakeup();
                    153:                        }
                    154:                }
                    155:        }
                    156: }
                    157: 
                    158: // 内部の割り込みマップ (Intmap) をネゲートする。
                    159: void
                    160: MPU64180Device::NegateIntmap(int source)
                    161: {
                    162:        uint32 oldmap;
                    163:        uint32 srcmap;
                    164: 
                    165:        oldmap = intmap;
                    166:        srcmap = 1U << (31 - source);
                    167:        intmap &= ~srcmap;
                    168: 
                    169:        if ((oldmap ^ intmap) != 0) {
                    170:                // 今は立ち下がりで何もすることはない。
                    171:        }
                    172: }
                    173: 
                    174: // INT0 信号線をアサートする。(PIO1 から呼ばれる)
                    175: void
                    176: MPU64180Device::AssertINT0()
                    177: {
                    178:        AssertIntmap(HD647180::IntmapINT0);
                    179: }
                    180: 
                    181: // INT0 信号線をネゲートする。
                    182: void
                    183: MPU64180Device::NegateINT0()
                    184: {
                    185:        NegateIntmap(HD647180::IntmapINT0);
                    186: }
                    187: 
                    188: // マスカブル割り込みを処理する。(命令境界で呼ばれる)
                    189: void
                    190: MPU64180Device::DoInterrupt()
                    191: {
                    192:        // まず割り込み禁止。
                    193:        ief1 = false;
                    194:        ief2 = false;
                    195: 
                    196:        // 優先順位の最も高い割り込みを一つ選択。
                    197:        assert(intmap != 0);
1.1.1.2 ! root      198:        uint source = __builtin_clz(intmap);
1.1       root      199: 
                    200:        // TRAP はここに来ない。NMI は LUNA では未接続のため未実装。
                    201:        assert(source != HD647180::IntmapTRAP);
                    202:        assert(source != HD647180::IntmapNMI);
                    203: 
                    204:        if (source == HD647180::IntmapINT0) {
                    205:                // INT0 はモードによって分岐方法が異なる。
                    206: 
                    207:                // ただし mode0 と mode2 は使われてないので未対応。
                    208:                if (int0mode != 1) {
1.1.1.2 ! root      209:                        PANIC("INT0 on mode%u (NOT IMPLEMENTED)", int0mode);
1.1       root      210:                }
                    211: 
                    212:                // mode1 は固定番地へ
1.1.1.2 ! root      213:                Push2(reg.pc);
1.1       root      214:                ExceptionDirect(source, 0x0038);
                    215:        } else {
                    216:                // 残りはすべてベクタ方式。
                    217: 
1.1.1.2 ! root      218:                Push2(reg.pc);
1.1       root      219:                ExceptionVector(source);
                    220:        }
                    221: 
                    222:        // XXX あとで見る
                    223:        // HD64180.pdf, p45. Figure 2.7.7
                    224:        CYCLE(11);
                    225: }
                    226: 
                    227: // 例外によって new_addr に直接ジャンプする。
                    228: // (HD64180 系の用語では例外ではなくて割り込みだが)
                    229: // source は Intmap*。
                    230: void
                    231: MPU64180Device::ExceptionDirect(int source, uint32 new_addr)
                    232: {
                    233:        // 例外発生とジャンプを記録。
                    234:        brhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source);
                    235:        exhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source);
                    236: 
                    237:        reg.pc = new_addr;
                    238: 
                    239:        debugger->NotifyExceptionXP(source);
                    240: }
                    241: 
                    242: // 例外ごとに固有のベクタにジャンプする。
                    243: // (HD64180 系の用語では例外ではなくて割り込みだが)
                    244: // source は Intmap*。
                    245: void
                    246: MPU64180Device::ExceptionVector(int source)
                    247: {
                    248:        // 固定コード
                    249:        static uint16 vector_offset[] = {
                    250:                0,              // 0:TRAP
                    251:                0,              // 1:NMI
                    252:                0,              // 2:INT0
                    253: 
                    254:                0x00,   // 3:INT1
                    255:                0x02,   // 4:INT2
                    256:                0x12,   // 5:Input Capture
                    257:                0x14,   // 6:Output Compare
                    258:                0x16,   // 7:Timer Overflow
                    259:                0x04,   // 8:Timer0 (PRT0)
                    260:                0x06,   // 9:Timer1 (PRT1)
                    261:                0x08,   // 10:DMA0
                    262:                0x0a,   // 11:DMA1
                    263:                0x0c,   // 12:CSIO
                    264:                0x0e,   // 13:ASCI0
                    265:                0x10,   // 14:ASCI1
                    266:        };
                    267: 
                    268:        // 例外からベクタアドレスを求める。ベクタアドレスは以下の構成。
                    269:        //
                    270:        //   F  E  D  C  B  A  9  8  7  6  5  4  3  2  1  0
                    271:        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
                    272:        // |      I レジスタ       |  IL    |  固定コード  |
                    273:        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
                    274:        assert(source < countof(vector_offset));
                    275:        uint32 vec_addr = (reg_i << 8) | intvec_low | vector_offset[source];
                    276: 
                    277:        // 例外発生を記録。
                    278:        brhist.AddEntry(GetPPC(), -1, 0x80000000 | source);
                    279:        exhist.AddEntry(GetPPC(), -1, 0x80000000 | source);
                    280: 
                    281:        // ジャンプ先を読み込む
1.1.1.2 ! root      282:        uint32 new_addr = Read2(vec_addr);
1.1       root      283: 
                    284:        // ベクタジャンプを記録。
                    285:        brhist.AddEntry(vec_addr, new_addr, -1);
                    286: 
                    287:        reg.pc = new_addr;
                    288: 
                    289:        debugger->NotifyExceptionXP(source);
                    290: }
                    291: 
                    292: 
                    293: //
                    294: // hd64180flag
                    295: //
                    296: 
                    297: // F レジスタの値を取得する
                    298: uint8
                    299: hd64180flag::Get() const
                    300: {
                    301:        uint8 f = 0;
                    302: 
                    303:        if (IsS())      f |= HD64180::FlagS;
                    304:        if (IsZ())      f |= HD64180::FlagZ;
                    305:        if (b5)         f |= 0x20;
                    306:        if (IsH())      f |= HD64180::FlagH;
                    307:        if (b3)         f |= 0x08;
                    308:        if (IsPV())     f |= HD64180::FlagPV;
                    309:        if (IsN())      f |= HD64180::FlagN;
                    310:        if (IsC())      f |= HD64180::FlagC;
                    311: 
                    312:        return f;
                    313: }
                    314: 
                    315: // F レジスタに代入する
                    316: void
                    317: hd64180flag::Set(uint8 val)
                    318: {
                    319:        SetS(val & HD64180::FlagS);
                    320:        SetZ(val & HD64180::FlagZ);
                    321:        b5 = (val & 0x20);
                    322:        SetH(val & HD64180::FlagH);
                    323:        b3 = (val & 0x08);
                    324:        SetPV(val & HD64180::FlagPV);
                    325:        SetN(val & HD64180::FlagN);
                    326:        SetC(val & HD64180::FlagC);
                    327: }
                    328: 
                    329: // fff (0..7) の条件が成立すれば true を返す。
                    330: bool
                    331: hd64180flag::IsCond(uint fff) const
                    332: {
                    333:        switch (fff) {
                    334:         case 0:        return !IsZ();  // NZ
                    335:         case 1:        return IsZ();   // Z
                    336:         case 2:        return !IsC();  // NC
                    337:         case 3:        return IsC();   // C
                    338:         case 4:        return !IsPV(); // PO
                    339:         case 5:        return IsPV();  // PE
                    340:         case 6:        return !IsS();  // P
                    341:         case 7:        return IsS();   // M
                    342:         default:
                    343:                PANIC("invalid cond = %u", fff);
                    344:        }
                    345: }

unix.superglobalmegacorp.com

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