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

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バイト命令しかないはず。
1.1.1.4   root      113:        // 上位ワードは $0000。
                    114:        uint32 info;
1.1       root      115:        if (ops[0] == 0xed || ops[0] == 0xdd || ops[0] == 0xfd) {
1.1.1.4   root      116:                info = (ops[0] << 8) | ops[1];
1.1       root      117:        } else {
1.1.1.4   root      118:                info = (ops[0] << 8);
1.1       root      119:        }
                    120: 
1.1.1.4   root      121:        brhist.AddEntry(GetPPC(), addr, info);
1.1       root      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: 
1.1.1.5 ! root      195: // ASCIn 割り込みをアサート/ネゲートする。
        !           196: // IEF1 はこちらで加味する。
        !           197: void
        !           198: MPU64180Device::ChangeASCIInt(uint n, bool asci_req)
        !           199: {
        !           200:        uint32 map = HD647180::IntmapASCI(n);
        !           201: 
        !           202:        if ((asci_req && GetIEF1())) {
        !           203:                AssertIntmap(map);
        !           204:        } else {
        !           205:                NegateIntmap(map);
        !           206:        }
        !           207: }
        !           208: 
1.1       root      209: // マスカブル割り込みを処理する。(命令境界で呼ばれる)
                    210: void
                    211: MPU64180Device::DoInterrupt()
                    212: {
                    213:        // まず割り込み禁止。
                    214:        ief1 = false;
                    215:        ief2 = false;
                    216: 
                    217:        // 優先順位の最も高い割り込みを一つ選択。
                    218:        assert(intmap != 0);
1.1.1.2   root      219:        uint source = __builtin_clz(intmap);
1.1       root      220: 
                    221:        // TRAP はここに来ない。NMI は LUNA では未接続のため未実装。
                    222:        assert(source != HD647180::IntmapTRAP);
                    223:        assert(source != HD647180::IntmapNMI);
                    224: 
                    225:        if (source == HD647180::IntmapINT0) {
                    226:                // INT0 はモードによって分岐方法が異なる。
                    227: 
                    228:                // ただし mode0 と mode2 は使われてないので未対応。
                    229:                if (int0mode != 1) {
1.1.1.2   root      230:                        PANIC("INT0 on mode%u (NOT IMPLEMENTED)", int0mode);
1.1       root      231:                }
                    232: 
                    233:                // mode1 は固定番地へ
1.1.1.2   root      234:                Push2(reg.pc);
1.1       root      235:                ExceptionDirect(source, 0x0038);
                    236:        } else {
                    237:                // 残りはすべてベクタ方式。
                    238: 
1.1.1.2   root      239:                Push2(reg.pc);
1.1       root      240:                ExceptionVector(source);
                    241:        }
                    242: 
                    243:        // XXX あとで見る
                    244:        // HD64180.pdf, p45. Figure 2.7.7
                    245:        CYCLE(11);
                    246: }
                    247: 
                    248: // 例外によって new_addr に直接ジャンプする。
                    249: // (HD64180 系の用語では例外ではなくて割り込みだが)
                    250: // source は Intmap*。
                    251: void
                    252: MPU64180Device::ExceptionDirect(int source, uint32 new_addr)
                    253: {
                    254:        // 例外発生とジャンプを記録。
                    255:        brhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source);
                    256:        exhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source);
                    257: 
                    258:        reg.pc = new_addr;
                    259: 
                    260:        debugger->NotifyExceptionXP(source);
                    261: }
                    262: 
                    263: // 例外ごとに固有のベクタにジャンプする。
                    264: // (HD64180 系の用語では例外ではなくて割り込みだが)
                    265: // source は Intmap*。
                    266: void
                    267: MPU64180Device::ExceptionVector(int source)
                    268: {
                    269:        // 固定コード
                    270:        static uint16 vector_offset[] = {
                    271:                0,              // 0:TRAP
                    272:                0,              // 1:NMI
                    273:                0,              // 2:INT0
                    274: 
                    275:                0x00,   // 3:INT1
                    276:                0x02,   // 4:INT2
                    277:                0x12,   // 5:Input Capture
                    278:                0x14,   // 6:Output Compare
                    279:                0x16,   // 7:Timer Overflow
                    280:                0x04,   // 8:Timer0 (PRT0)
                    281:                0x06,   // 9:Timer1 (PRT1)
                    282:                0x08,   // 10:DMA0
                    283:                0x0a,   // 11:DMA1
                    284:                0x0c,   // 12:CSIO
                    285:                0x0e,   // 13:ASCI0
                    286:                0x10,   // 14:ASCI1
                    287:        };
                    288: 
                    289:        // 例外からベクタアドレスを求める。ベクタアドレスは以下の構成。
                    290:        //
                    291:        //   F  E  D  C  B  A  9  8  7  6  5  4  3  2  1  0
                    292:        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
                    293:        // |      I レジスタ       |  IL    |  固定コード  |
                    294:        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
                    295:        assert(source < countof(vector_offset));
                    296:        uint32 vec_addr = (reg_i << 8) | intvec_low | vector_offset[source];
                    297: 
                    298:        // 例外発生を記録。
                    299:        brhist.AddEntry(GetPPC(), -1, 0x80000000 | source);
                    300:        exhist.AddEntry(GetPPC(), -1, 0x80000000 | source);
                    301: 
                    302:        // ジャンプ先を読み込む
1.1.1.2   root      303:        uint32 new_addr = Read2(vec_addr);
1.1       root      304: 
                    305:        // ベクタジャンプを記録。
                    306:        brhist.AddEntry(vec_addr, new_addr, -1);
                    307: 
                    308:        reg.pc = new_addr;
                    309: 
                    310:        debugger->NotifyExceptionXP(source);
                    311: }
                    312: 
                    313: 
                    314: //
                    315: // hd64180flag
                    316: //
                    317: 
                    318: // F レジスタの値を取得する
                    319: uint8
                    320: hd64180flag::Get() const
                    321: {
                    322:        uint8 f = 0;
                    323: 
                    324:        if (IsS())      f |= HD64180::FlagS;
                    325:        if (IsZ())      f |= HD64180::FlagZ;
                    326:        if (b5)         f |= 0x20;
                    327:        if (IsH())      f |= HD64180::FlagH;
                    328:        if (b3)         f |= 0x08;
                    329:        if (IsPV())     f |= HD64180::FlagPV;
                    330:        if (IsN())      f |= HD64180::FlagN;
                    331:        if (IsC())      f |= HD64180::FlagC;
                    332: 
                    333:        return f;
                    334: }
                    335: 
                    336: // F レジスタに代入する
                    337: void
                    338: hd64180flag::Set(uint8 val)
                    339: {
                    340:        SetS(val & HD64180::FlagS);
                    341:        SetZ(val & HD64180::FlagZ);
                    342:        b5 = (val & 0x20);
                    343:        SetH(val & HD64180::FlagH);
                    344:        b3 = (val & 0x08);
                    345:        SetPV(val & HD64180::FlagPV);
                    346:        SetN(val & HD64180::FlagN);
                    347:        SetC(val & HD64180::FlagC);
                    348: }
                    349: 
                    350: // fff (0..7) の条件が成立すれば true を返す。
                    351: bool
                    352: hd64180flag::IsCond(uint fff) const
                    353: {
                    354:        switch (fff) {
                    355:         case 0:        return !IsZ();  // NZ
                    356:         case 1:        return IsZ();   // Z
                    357:         case 2:        return !IsC();  // NC
                    358:         case 3:        return IsC();   // C
                    359:         case 4:        return !IsPV(); // PO
                    360:         case 5:        return IsPV();  // PE
                    361:         case 6:        return !IsS();  // P
                    362:         case 7:        return IsS();   // M
                    363:         default:
                    364:                PANIC("invalid cond = %u", fff);
                    365:        }
                    366: }

unix.superglobalmegacorp.com

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