Annotation of nono/vm/mpu680x0.h, revision 1.1.1.14

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.10  root        7: //
                      8: // MPU (MC68030)
                      9: //
1.1       root       10: 
                     11: #pragma once
                     12: 
                     13: #include "mpu.h"
1.1.1.11  root       14: #include "branchhistory.h"
1.1.1.13  root       15: #include "bus.h"
1.1.1.11  root       16: #include "event.h"
1.1       root       17: #include "m68030.h"
1.1.1.11  root       18: #include "m68030mmu.h"
                     19: 
                     20: class InterruptDevice;
1.1.1.13  root       21: class m68030Cache;
1.1.1.14! root       22: struct m68030CacheLine;
1.1       root       23: 
1.1.1.14! root       24: class MPU680x0Device : public MainMPUDevice
1.1       root       25: {
1.1.1.14! root       26:        using inherited = MainMPUDevice;
1.1.1.11  root       27:        friend class m68030MMU;
                     28: 
                     29:        // CPU の実行状態
                     30:        static const uint32 CPU_STATE_NORMAL    = 0;
                     31:        static const uint32 CPU_STATE_STOP              = 1;
                     32:        static const uint32 CPU_STATE_HALT              = 2;
                     33: 
1.1       root       34:  public:
1.1.1.7   root       35:        MPU680x0Device();
1.1.1.13  root       36:        ~MPU680x0Device() override;
1.1       root       37: 
1.1.1.13  root       38:        void SetLogLevel(int loglevel_) override;
1.1.1.2   root       39:        bool Init() override;
1.1.1.10  root       40:        void ResetHard(bool poweron) override;
1.1       root       41: 
                     42:        // 現在の PPC を取得
1.1.1.11  root       43:        uint32 GetPPC() const override { return ppc; }
1.1       root       44: 
1.1.1.10  root       45:        // 現在の VBR を取得
1.1.1.11  root       46:        uint32 GetVBR() const override { return reg.vbr; }
                     47: 
1.1.1.13  root       48:        // MPU 名を取得
                     49:        const char *GetMPUName() const override { return "MC68030"; }
                     50: 
1.1.1.11  root       51:        bool IsSuper() const    { return reg.s; }
                     52:        bool IsMaster() const   { return reg.m; }
                     53: 
                     54:        // CPU の実行状態 (uint32) を返す。
                     55:        uint32 GetState() const { return cpu_state; }
1.1.1.10  root       56: 
1.1       root       57:        // 現在アクセス中の論理アドレス、物理アドレスを取得。
1.1.1.13  root       58:        uint32 GetLaddr() const override { return bus.laddr.Addr(); }
                     59:        uint32 GetPaddr() const override { return bus.paddr.Addr(); }
1.1       root       60: 
1.1.1.5   root       61:        // 割り込みレベルが変わったことを MPU に通知
                     62:        void Interrupt(int level) override;
1.1       root       63: 
                     64:        // A-Line, F-Line 命令エミュレーションのコールバックを指定する。
                     65:        // (Human68k エミュレーションで使用)
1.1.1.11  root       66:        void SetALineCallback(bool (*callback)(MPU680x0Device*, void*), void *arg);
                     67:        void SetFLineCallback(bool (*callback)(MPU680x0Device*, void*), void *arg);
1.1       root       68: 
                     69:        // FPU を持っているか
1.1.1.11  root       70:        bool HaveFPU() const { return has_fpu; }
1.1       root       71: 
1.1.1.14! root       72:        // バーストアクセスをサポートするか
        !            73:        void EnableBurstAccess(bool enable) { has_burst_access = enable; }
        !            74: 
1.1.1.13  root       75:        void SetCI() override {
                     76:                bus.ci = true;
                     77:        }
1.1.1.9   root       78: 
1.1.1.11  root       79:        // ホールト
1.1.1.10  root       80:        void Halt();
                     81: 
1.1.1.11  root       82:        // 基本アクセス。内部から使用する。
                     83:        // アドレスは論理アドレスで、空間は現在の命令/データ空間。
                     84:        // バスエラーなら C++ の例外をスローする。
1.1.1.14! root       85:        uint32 fetch_2();
        !            86:        uint32 fetch_4();
        !            87:        uint32 read_n(uint32 laddr, uint size) {
        !            88:                busaddr addr =
        !            89:                        busaddr(laddr) | fc_data | BusAddr::R | busaddr::Size(size);
        !            90:                return read_data(addr);
        !            91:        }
        !            92:        void write_n(uint32 laddr, uint size, uint32 data) {
        !            93:                busaddr addr =
        !            94:                        busaddr(laddr) | fc_data | BusAddr::W | busaddr::Size(size);
        !            95:                write_data(addr, data);
        !            96:        }
        !            97:        uint32 read_1(uint32 laddr) { return read_n(laddr, 1); }
        !            98:        uint32 read_2(uint32 laddr) { return read_n(laddr, 2); }
        !            99:        uint32 read_4(uint32 laddr) { return read_n(laddr, 4); }
        !           100:        void write_1(uint32 laddr, uint32 data) { write_n(laddr, 1, data); }
        !           101:        void write_2(uint32 laddr, uint32 data) { write_n(laddr, 2, data); }
        !           102:        void write_4(uint32 laddr, uint32 data) { write_n(laddr, 4, data); }
1.1.1.11  root      103: 
                    104:        // MMU アクセス
1.1.1.13  root      105:        busaddr TranslatePeek(busaddr laddr);
1.1.1.14! root      106:        // 統計
        !           107:        void CalcStat();
1.1.1.11  root      108: 
                    109:        // レジスタ
                    110:        uint16 GetIR() const    { return ir; }
                    111:        uint16 GetIR2() const   { return ir2; }
                    112:        // SR を変更する (Human68k から使う)
                    113:        void SetSR(uint16);
                    114:        uint16 GetSR() const    { return reg.GetSR(); }
                    115: 
                    116:        uint64 GetSRP()  const { return reg.srp.q; }
                    117:        uint32 GetSRPh() const { return reg.srp.h; }
                    118:        uint32 GetSRPl() const { return reg.srp.l; }
                    119:        uint64 GetCRP()  const { return reg.crp.q; }
                    120:        uint32 GetCRPh() const { return reg.crp.h; }
                    121:        uint32 GetCRPl() const { return reg.crp.l; }
                    122:        uint64 GetTT(int idx) const { return reg.tt[idx]; }
                    123:        uint32 GetTC() const { return reg.tc; }
                    124:        uint16 GetMMUSR() const { return reg.mmusr; }
                    125: 
1.1       root      126:  private:
1.1.1.10  root      127:        // リセット例外コールバック
                    128:        void ResetCallback(Event& ev);
                    129: 
                    130:        // 命令実行系コールバック
                    131:        void ExecShort(Event& ev);
                    132:        void ExecFull(Event& ev);
                    133:        void ExecTrace(Event& ev);
1.1.1.5   root      134: 
1.1.1.10  root      135:        // トレース設定。デバッガから呼び出される。
                    136:        void SetTrace(bool trace_on) override;
1.1.1.9   root      137: 
1.1.1.10  root      138:        // 割り込みイベントコールバック
                    139:        void InterruptCallback(Event& ev);
                    140: 
1.1.1.11  root      141:        // 動作モード変更
                    142:        void ChangeState(uint32 new_state);
1.1.1.8   root      143: 
1.1.1.11  root      144:        // 次の実行サイクルを Full にする。
                    145:        void MakeNextFull();
1.1.1.8   root      146: 
1.1.1.11  root      147:        inline void CYCLE(int cc) {
                    148:                used_cycle += cc;
                    149:        }
                    150:        inline void CYCLE2(int cc, int ncc) {
                    151:                used_cycle += cc;
                    152:                cycle_nocache += ncc - cc;
                    153:        }
                    154: 
                    155:        // PC を addr に変更する。
                    156:        // ベクタへのジャンプはここではなく JumpVector()。
                    157:        inline void Jump(uint32 addr) {
                    158:                // 先にブランチ履歴に記録
1.1.1.12  root      159:                brhist.AddEntry(ppc | (IsSuper() ? 1 : 0), addr, ir);
1.1.1.11  root      160: 
                    161:                if (__predict_false((addr & 1) != 0)) {
1.1.1.12  root      162:                        ExceptionBuserr(M68K::EXCEP_ADDRERR);
1.1.1.11  root      163:                        return;
                    164:                }
                    165:                reg.pc = addr;
                    166:        }
                    167: 
                    168:        // -(An) 実行前にレジスタを保存する。
                    169:        // バスエラーからの復帰用。
                    170:        inline void save_reg_pd(int n) {
                    171:                // 該当ビットのフラグを立てる
                    172:                flag_pd |= (1 << n);
                    173: 
                    174:                // 保存
                    175:                save_pd[n] = reg.A[n];
                    176:        }
                    177: 
                    178:        // (An)+ 実行前にレジスタを保存する。
                    179:        // バスエラーからの復帰用。
                    180:        inline void save_reg_pi(int n) {
                    181:                // 該当ビットのフラグを立てる
                    182:                flag_pi |= (1 << n);
                    183: 
                    184:                // 保存
                    185:                save_pi[n] = reg.A[n];
                    186:        }
                    187: 
1.1.1.14! root      188:        // -(An) 実行前にレジスタを(まだ保存してなければ)保存する。
        !           189:        // 1命令で同じレジスタを2回 -(An) する可能性がある命令用。
        !           190:        inline void save_reg_pd_if(int n) {
        !           191:                if ((flag_pd & (1 << n)) == 0) {
        !           192:                        save_reg_pd(n);
        !           193:                }
        !           194:        }
        !           195:        // (An)+ 実行前にレジスタを(まだ保存してなければ)保存する。
        !           196:        // 1命令で同じレジスタを2回 (An)+ する可能性がある命令用。
        !           197:        inline void save_reg_pi_if(int n) {
        !           198:                if ((flag_pi & (1 << n)) == 0) {
        !           199:                        save_reg_pi(n);
        !           200:                }
        !           201:        }
        !           202: 
1.1.1.11  root      203:        void restore_reg_pi();
                    204:        void restore_reg_pd();
1.1.1.14! root      205:        void JumpVector(uint vector, bool from_buserr);
1.1.1.11  root      206: 
                    207:  protected:
                    208: #include "m68030ea.h"
                    209: 
                    210:  private:
                    211:        // 基本アクセスルーチンを使った便利サブルーチン
1.1.1.14! root      212:        inline void push_2(uint32 data) {
1.1.1.11  root      213:                reg.A[7] -= 2;
1.1.1.14! root      214:                write_2(reg.A[7], data);
1.1.1.11  root      215:        }
1.1.1.14! root      216:        inline void push_4(uint32 data) {
1.1.1.11  root      217:                reg.A[7] -= 4;
1.1.1.14! root      218:                write_4(reg.A[7], data);
1.1.1.11  root      219:        }
1.1.1.14! root      220:        inline uint32 pop_2() {
        !           221:                uint32 data = read_2(reg.A[7]);
1.1.1.11  root      222:                reg.A[7] += 2;
                    223:                return data;
                    224:        }
1.1.1.14! root      225:        inline uint32 pop_4() {
        !           226:                uint32 data = read_4(reg.A[7]);
1.1.1.11  root      227:                reg.A[7] += 4;
                    228:                return data;
                    229:        }
                    230: 
1.1.1.13  root      231:        // バスアクセス
1.1.1.14! root      232:        uint32 read_data(busaddr addr);
        !           233:        busdata read_nocache(busaddr addr);
        !           234:        busdata read_cache(m68030Cache *cache, busaddr addr);
        !           235:        busdata read_line(m68030CacheLine *, uint32 tag, uint32 opermask);
        !           236:        busdata read_single(busdata bd, uint32 readmask, uint32 opermask);
        !           237: 
        !           238:        void write_data(busaddr addr, uint32 data);
        !           239:        busdata write_bus(busaddr addr, uint32 data);
        !           240: 
        !           241:        busdata read_phys();
        !           242:        busdata write_phys(uint32 data);
        !           243:        bool read_phys_burst(uint32 *dst);
1.1.1.13  root      244: 
1.1.1.11  root      245: #define OP_PROTO(name) void __CONCAT(op_,name)()
                    246: #include "m68030ops.h"
                    247: #undef OP_PROTO
                    248: 
1.1.1.14! root      249:        void ops_divu_32_32(uint r, uint q);
        !           250:        void ops_divu_64_32(uint r, uint q);
        !           251:        void ops_divs_32_32(uint r, uint q);
        !           252:        void ops_divs_64_32(uint r, uint q);
1.1.1.11  root      253:        void ops_movec_rc_rn();
                    254:        void ops_movec_rn_rc();
                    255:        void ops_movep();
                    256:        // もともとソース内のテンプレートだった
                    257:        void ops_movem_list_ea(int bytesize);
                    258:        void ops_movem_ea_list(int bytesize);
                    259:        void ops_trapcc(uint cond);
                    260:        inline void ops_bra();
                    261: 
                    262:        // 68030core.cpp
                    263:        void ops_rte();
                    264:        void ops_stop();
                    265:        // vm/mpu680x0.cpp
                    266:        void ops_reset();
                    267: 
                    268: #include "m68030fpu.h"
                    269:        void fpu_op_start();
                    270: 
1.1.1.13  root      271:        // キャッシュ
                    272:        void SetCACR(uint32);
                    273: 
1.1.1.11  root      274:        // MMU
                    275:        bool SetSRP(uint32, uint32);
                    276:        bool SetCRP(uint32, uint32);
                    277:        void SetTT(int idx, uint32);
                    278:        bool SetTC(uint32);
                    279:        void SetMMUSR(uint16);
                    280: 
                    281:        bool TranslateRead();
                    282:        bool TranslateWrite();
                    283: 
1.1.1.13  root      284:        bool CheckTT();
1.1.1.11  root      285:        uint32 get_fc();
                    286:        void mmu_op_illg2();
                    287:        void mmu_op_pflush();
                    288:        void mmu_op_pflush_ea();
                    289:        void mmu_op_pload();
                    290:        void mmu_op_ptest();
                    291:        // MMU 有効状態を更新。(TC と TT の変更で呼ばれる)
                    292:        void mmu_enable_changed();
                    293: 
                    294:        // 例外
1.1.1.14! root      295:        void GenerateExframe0(uint vector, uint32 pc, uint16 sr);
        !           296:        void GenerateExframe2(uint vector, uint16 sr);
        !           297:        void GenerateExframeB(uint vector, uint16 sr);
1.1.1.11  root      298:        int  ExceptionReset();
1.1.1.14! root      299:        void ExceptionBuserr(uint vector);
1.1.1.13  root      300:        uint64 ExceptionInterrupt();
1.1.1.12  root      301:        void ExceptionTrap15();
1.1.1.14! root      302:        void Exception(uint vector);
        !           303:        void ExceptionGeneric(uint vector, uint32 inst);
1.1.1.11  root      304: 
                    305:        // 二重バスフォールト
                    306:        void DoubleBusFault(const char *where);
                    307: 
                    308:  public:
                    309:        // レジスタ
                    310:        m68kreg reg {};
                    311: 
                    312:        // MMU work
                    313:        m68030TT mmu_tt[2] /*{}*/;
                    314:        m68030TC mmu_tc /*{}*/;
                    315:        m68030ATC atc {this};
                    316:        bool mmu_enable {};             // MMU が有効なら true
                    317: 
                    318:        // バス
                    319:        m68kbus bus {};
1.1.1.13  root      320:        // 現在の特権状態でのプログラム空間とデータ空間アクセス用。
                    321:        busaddr fc_inst {};             // こっちは R 含む
                    322:        busaddr fc_data {};             // こっちは R/W 含まない
1.1.1.11  root      323: 
                    324:  private:
                    325:        uint16 ir {};
                    326:        uint16 ir2 {};
                    327:        // 現在実行中の命令の先頭アドレス
                    328:        uint32 ppc {};
                    329: 
                    330:        // レジスタ(状態保存用)
                    331:        uint32 save_pd[8] {};   // -(An) を保存
                    332:        uint32 save_pi[8] {};   // (An)+ を保存
                    333:        uint8  flag_pd {};              // -(An) のどのレジスタを保存したか
                    334:        uint8  flag_pi {};              // (An)+ のどのレジスタを保存したか
                    335: 
1.1.1.13  root      336:        // キャッシュ
                    337:        std::unique_ptr<m68030Cache> icache /*{}*/;
1.1.1.14! root      338:        std::unique_ptr<m68030Cache> dcache /*{}*/;
1.1.1.13  root      339: 
1.1.1.11  root      340:        // FPU
                    341:        int has_fpu {};                 // 0:FPUなし、1:68881、2:68882(?)
                    342:        bool fpu_dirty {};
                    343:        struct fpemu fe {};
                    344: 
                    345:        // CPU の実行状態
                    346:        uint32 cpu_state {};
1.1.1.7   root      347: 
1.1.1.10  root      348:        // 割り込みペンディング
                    349:        bool intr_pending {};
                    350: 
1.1.1.11  root      351:        // 現在の外部割り込みレベル
                    352:        int intr_level {};
                    353: 
                    354:        // 電源オンからの累積消費サイクル
                    355:        uint64 used_cycle {};
                    356: 
1.1.1.13  root      357:        // 今回のバスウェイト [nsec]
                    358:        uint64 buswait {};
                    359: 
1.1.1.14! root      360:        // 外部バスがバースト転送に対応していれば true
        !           361:        bool has_burst_access {};
        !           362: 
1.1.1.11  root      363:        int32 cycle_nocache {};         // ノーキャッシュケースの時の追加分
                    364: 
                    365:        // A-Line, F-Line 命令エミュレーションのコールバックとユーザ引数。
                    366:        // ユーザ引数には関与しないので呼び出し側が自由に指定してよい。
                    367:        // コールバック側で処理完了したら true を返す。
                    368:        // デフォルトの処理(すなわちm68k例外)にする場合は false を返す。
                    369:        bool (*aline_callback)(MPU680x0Device *, void *) {};
                    370:        void *aline_arg {};
                    371:        bool (*fline_callback)(MPU680x0Device *, void *) {};
                    372:        void *fline_arg {};
                    373: 
                    374:        // ブランチ履歴 (例外履歴を含む)
                    375:        BranchHistory_m680x0 brhist { OBJ_MPU_BRHIST };
                    376:        // 例外履歴のみ
                    377:        BranchHistory_m680x0 exhist { OBJ_MPU_EXHIST };
                    378: 
                    379:        // 割り込みイベント
                    380:        Event intr_event { this };
                    381: 
1.1.1.10  root      382:        // トレースでコールバックを差し替えることができるように
                    383:        // イベントコールバックを変数に入れてある
                    384:        EventCallback_t exec_short {};
                    385:        EventCallback_t exec_full {};
1.1.1.4   root      386: 
1.1.1.11  root      387:        // レジスタモニター
                    388:        DECLARE_MONITOR_CALLBACK(MonitorUpdateReg);
1.1.1.14! root      389:        void MonitorUpdateFPU(TextScreen&, int y, m68kreg&);
1.1.1.11  root      390:        Monitor reg_monitor { this };
                    391: 
                    392:        // ATC モニター
                    393:        DECLARE_MONITOR_CALLBACK(MonitorUpdateATC);
                    394:        Monitor atc_monitor { this };
                    395: 
1.1.1.13  root      396:        // キャッシュモニター
                    397:        DECLARE_MONITOR_CALLBACK(MonitorUpdateCache);
1.1.1.14! root      398:        int MonitorUpdateCache1(TextScreen&, int y, m68030Cache *,
        !           399:                char (*)(const m68030CacheLine&));
1.1.1.13  root      400:        Monitor cache_monitor { this };
                    401: 
1.1.1.11  root      402:        InterruptDevice *interruptdev {};
                    403:        VectorTable *vectortable {};
1.1       root      404: };
                    405: 
1.1.1.13  root      406: // これを呼びたい人は mpu を持ってるはず。
                    407: static inline MPU680x0Device *GetMPU680x0Device(Device *mpu_) {
                    408:        return dynamic_cast<MPU680x0Device*>(mpu_);
1.1.1.11  root      409: }

unix.superglobalmegacorp.com

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