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

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バイト目処理
        !            37:        op = Fetch8();
        !            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
        !            94:        Push16(reg.pc - 1);
        !            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);
        !           198:        int source = __builtin_clz(intmap);
        !           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) {
        !           209:                        PANIC("INT0 on mode%d (NOT IMPLEMENTED)", int0mode);
        !           210:                }
        !           211: 
        !           212:                // mode1 は固定番地へ
        !           213:                Push16(reg.pc);
        !           214:                ExceptionDirect(source, 0x0038);
        !           215:        } else {
        !           216:                // 残りはすべてベクタ方式。
        !           217: 
        !           218:                Push16(reg.pc);
        !           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:        // ジャンプ先を読み込む
        !           282:        uint32 new_addr = Read16(vec_addr);
        !           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.