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

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

unix.superglobalmegacorp.com

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