Annotation of nono/m680x0/m68030.h, revision 1.1.1.1

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2017 [email protected]
                      4: //
                      5: 
                      6: #pragma once
                      7: 
                      8: //
                      9: // 外部公開用
                     10: //
                     11: 
                     12: #include <atomic>
                     13: #include <mutex>
                     14: #include <sys/cdefs.h>
                     15: 
                     16: __BEGIN_DECLS
                     17: #include "fpu_emulate.h"
                     18: __END_DECLS
                     19: 
                     20: class m68kcpu;
                     21: 
                     22: // 外部ループフラグ
                     23: // これらのフラグがいずれも立っていない間、CPU 実行は内側のディスパッチ
                     24: // ループを周り、どれかでも立てばディスパッチループを抜けてフラグを処理
                     25: // してから再びディスパッチループに戻る。
                     26: // それぞれ独立しているためビットを立てる際は代入ではなく OR すること。
                     27: #define CPU_REQ_STOP           (0x00000001)    // ストップ状態
                     28: #define CPU_REQ_HALT           (0x00000002)    // ホールト状態
                     29: #define CPU_REQ_TRACE          (0x00000004)    // デバッガ有効
                     30: #define CPU_REQ_PROMPT         (0x00000008)    // デバッガプロンプト
                     31: #define CPU_REQ_RELEASE                (0x00000010)    // 命令後に CPU 実行中断
                     32: #define CPU_REQ_INTR           (0x00000020)    // 命令後に割り込みチェックが必要
                     33: 
                     34: #define M68K_SR_T      (0xc000)
                     35: #define M68K_SR_S      (0x2000)
                     36: #define M68K_SR_M      (0x1000)
                     37: #define M68K_CCR_X     (0x0010)
                     38: #define M68K_CCR_N     (0x0008)
                     39: #define M68K_CCR_Z     (0x0004)
                     40: #define M68K_CCR_V     (0x0002)
                     41: #define M68K_CCR_C     (0x0001)
                     42: 
                     43: // SSW
                     44: #define SSW_SIZE(x)            (((x) & 0x03) << 4)
                     45: #define SSW_SIZE_BYTE  SSW_SIZE(1)
                     46: #define SSW_SIZE_WORD  SSW_SIZE(2)
                     47: #define SSW_SIZE_3BYTES        SSW_SIZE(3)
                     48: #define SSW_SIZE_LONG  SSW_SIZE(0)
                     49: #define SSW_SIZE_MASK  SSW_SIZE(0x03)
                     50: 
                     51: #define SSW_FC_MASK            (0x0007)        // FC_*
                     52: #define SSW_RW                 (0x0040)        // SSW_BUS_{R,W}
                     53: #define SSW_RM                 (0x0080)
                     54: #define SSW_DF                 (0x0100)        // Data Fault
                     55: #define SSW_RB                 (0x1000)
                     56: #define SSW_RC                 (0x2000)
                     57: #define SSW_FB                 (0x4000)
                     58: #define SSW_FC                 (0x8000)
                     59: 
                     60: #define SSW_BUS_R              (0x0040)
                     61: #define SSW_BUS_W              (0x0000)
                     62: 
                     63: #define FC_DATA                        (1)
                     64: #define FC_PROG                        (2)
                     65: #define FC_USER                        (0)
                     66: #define FC_SUPER               (4)
                     67: #define FC_UD                  (FC_USER  | FC_DATA)
                     68: #define FC_UP                  (FC_USER  | FC_PROG)
                     69: #define FC_SD                  (FC_SUPER | FC_DATA)
                     70: #define FC_SP                  (FC_SUPER | FC_PROG)
                     71: 
                     72: #define M68K_FPCR_MASK (0x0000fff0)
                     73: #define M68K_FPSR_MASK (0x0ffffff8)
                     74: 
                     75: #include "m68030ccr.h"
                     76: #include "m68030mmu.h"
                     77: 
                     78: // 64ビット数と2つの32ビット数を扱う共用体。
                     79: // 構造はまったく同じだが名前だけ場所に合わせてつけたい。
                     80: #if _BYTE_ORDER == _LITTLE_ENDIAN
                     81: #define DEF_UNION64(NAME, Q, H, L)     \
                     82:        union NAME {    \
                     83:                uint64 Q;       \
                     84:                struct { uint32 L, H; };        \
                     85:        }
                     86: #else
                     87: #define DEF_UNION64(NAME, Q, H, L)     \
                     88:        union NAME {    \
                     89:                uint64 Q;       \
                     90:                struct { uint32 H, L; };        \
                     91:        }
                     92: #endif
                     93: 
                     94: DEF_UNION64(union64, q, h, l);
                     95: 
                     96: // レジスタイメージを保持する構造体。
                     97: // この構造体はコピーとか比較をするのでポインタとかは置かないこと。
                     98: struct m68kreg {
                     99:  public:
                    100:        uint32 pc;
                    101:        uint32 da[16];
                    102: 
                    103:        m68030ccr ccr;
                    104:        bool s;                         // SR の S ビット
                    105:        bool m;                         // SR の M ビット
                    106:        int  intr_level;        // SR の割り込みレベル (0-7)
                    107: 
                    108:        // 現在の SP は常に da[15]。現在有効でない残り2つの SP をここに保存。
                    109:        // 例えばユーザ状態なら da[15] が USP、isp/msp は ISP/MSP を示し、
                    110:        // usp の内容は無効。
                    111:        uint32 usp;
                    112:        uint32 isp;
                    113:        uint32 msp;
                    114: 
                    115:        uint32 vbr;
                    116:        uint32 sfc;
                    117:        uint32 dfc;
                    118: 
                    119:        uint32 cacr;
                    120:        uint32 caar;
                    121: 
                    122:        union64 srp;
                    123:        union64 crp;
                    124:        uint32 tt[2];
                    125:        uint32 tc;
                    126:        uint16 mmusr;
                    127: 
                    128:        struct fpframe fpframe;
                    129: 
                    130:        // CPU の実行状態
                    131:        //  0            .. 通常状態
                    132:        //  CPU_REQ_STOP .. STOP 状態
                    133:        //  CPU_REQ_HALT .. HALT 状態
                    134:        uint32 state;
                    135: 
                    136:  public:
                    137:        // SR の上位8ビット部分のみを返す
                    138:        uint16 sr_h() {
                    139:                return (s ? M68K_SR_S : 0) | (m ? M68K_SR_M : 0) | (intr_level << 8);
                    140:        }
                    141: };
                    142: 
                    143: // ブランチ履歴
                    144: struct m68kbrhist {
                    145:        uint32 count;   // 連続通過回数
                    146:        uint32 from;    // ジャンプ元アドレス(VA)
                    147:        uint32 to;              // ジャンプ先アドレス(VA)
                    148:        uint32 padding;
                    149: } __packed;
                    150: 
                    151: // バス状態
                    152: struct m68kbus {
                    153:        // 論理アドレスと SSW。
                    154:        // SSW はアクセス前に SSW_BUS_{R,W} と FC[012] をセットすること。
                    155:        DEF_UNION64(, ssw_laddr, ssw, laddr);
                    156: 
                    157:        uint32 paddr;                   // 対応する物理アドレス
                    158:        // データバス。
                    159:        // 今の所書き込みだけで使う。読み込みデータは戻り値のみ。
                    160:        uint32 data;
                    161: 
                    162:        // SSW のうち現在の FC2 だけ別途覚えておく。
                    163:        // FC2 が変化するのは SR:S による特権モードが変わった時だけなので。
                    164:        uint16 fc2;
                    165: 
                    166:        // バスが Write なら true を返す
                    167:        bool IsWrite() const { return (ssw & SSW_BUS_R) == 0; }
                    168: 
                    169:        // このへんどうするか
                    170: 
                    171:        // FC2 をキャッシュしておく。
                    172:        void SetFC2(bool newfc2) {
                    173:                fc2 = newfc2 ? 4 : 0;
                    174:        }
                    175:        // FC を取得する。
                    176:        // これは MMU ルーチンから呼ばれる。そのためこの時点ではすでに
                    177:        // FC0/1 と FC2 は ssw に合成済みなので、これでよい。
                    178:        uint GetFC() const { return ssw & SSW_FC_MASK; }
                    179: };
                    180: 
                    181: class m68kcpu {
                    182:  public:
                    183:        m68kcpu() { }
                    184:        virtual ~m68kcpu() { }
                    185: 
                    186:  public:
                    187:        m68kreg reg {};
                    188:        uint32 ppc = 0;                 // 現在実行中の命令の先頭アドレス
                    189:        uint16 ir = 0;
                    190:        uint16 ir2 = 0;
                    191: 
                    192:        uint32 save_pd[8] {};   // -(An) を保存
                    193:        uint32 save_pi[8] {};   // (An)+ を保存
                    194:        uint8  flag_pd = 0;             // -(An) のどのレジスタを保存したか
                    195:        uint8  flag_pi = 0;             // (An)+ のどのレジスタを保存したか
                    196: 
                    197:        // MMU 状態
                    198:        bool mmu_enable = false;
                    199:        // SRP
                    200:        void SetSRP(uint32, uint32);
                    201:        uint64 GetSRP()  const { return reg.srp.q; }
                    202:        uint32 GetSRPh() const { return reg.srp.h; }
                    203:        uint32 GetSRPl() const { return reg.srp.l; }
                    204:        // CRP
                    205:        void SetCRP(uint32, uint32);
                    206:        uint64 GetCRP()  const { return reg.crp.q; }
                    207:        uint32 GetCRPh() const { return reg.crp.h; }
                    208:        uint32 GetCRPl() const { return reg.crp.l; }
                    209:        // TT
                    210:        void SetTT(int idx, uint32);
                    211:        uint64 GetTT(int idx) const { return reg.tt[idx]; }
                    212:        // TC
                    213:        bool SetTC(uint32);
                    214:        uint32 GetTC() const { return reg.tc; }
                    215:        // MMUSR
                    216:        void SetMMUSR(uint16);
                    217:        uint16 GetMMUSR() const { return reg.mmusr; }
                    218:        // MMU work
                    219:        m68030TT mmu_tt[2];
                    220:        uint8 mmu_tt_quick[256] {};
                    221:        m68030TC mmu_tc;
                    222:        m68030ATC atc {this};
                    223: 
                    224:  private:
                    225:        void mmu_enable_changed();
                    226: 
                    227:  public:
                    228:        int has_fpu = 0;                // 0:FPUなし、1:68881、2:68882(?)
                    229:        bool fpu_dirty = false;
                    230:        struct fpemu fe {};
                    231: 
                    232:        std::atomic<uint32> atomic_reqflag {}; // 外部ループ & リクエストフラグ
                    233: 
                    234:        // 割り込みペンディング
                    235:        // intr_vector[1] がレベル1割り込みのペンディング中ベクタ
                    236:        //  :
                    237:        // intr_vector[7] がレベル7割り込みのペンディング中ベクタ
                    238:        //
                    239:        // [0] を intr_pending (割り込みペンディング) として使う。
                    240:        // ペンディングになっているレベルのビットを立てる。
                    241:        //
                    242:        //   bit  7  6  5  4  3  2  1  0
                    243:        // Level  0  1  2  3  4  5  6  7
                    244:        //
                    245:        // intrmtx 取ってからアクセスすること。
                    246:        uint8 intr_vector[8] {};
                    247: #define intr_pending intr_vector[0]
                    248: 
                    249:        // 割り込みマスク
                    250:        // 現在の割り込みレベルで割り込みを受け付けるレベルのビットを立てる
                    251:        // I=0 だと割り込みレベル 1..7 を受け付けるので %01111111
                    252:        // I=5 だと割り込みレベル  6,7 を受け付けるので %00000011
                    253:        // I=6 だと割り込みレベル    7 を受け付けるので %00000001
                    254:        // ただし I=7 はこれを使わず別処理する
                    255:        //   bit  7  6  5  4  3  2  1  0
                    256:        // Level  0  1  2  3  4  5  6  7
                    257:        //
                    258:        // intrmtx 取ってからアクセスすること。
                    259:        uint8 intr_mask = 0;
                    260: 
                    261:        // 割り込み要求は別スレッドから呼ばれる場合もあるので
                    262:        // (自スレッドから呼び出した関数の向こうから呼ばれる場合もあることに注意)
                    263:        // それらの変数はこれで保護する。
                    264:        // 最終的には atomic_reqflag に CPU_REQ_INTR を立てることでメインループ
                    265:        // に通知する (この通知そのものは atomic なので特に保護しなくてもよい)。
                    266:        std::mutex intrmtx {};
                    267: 
                    268:        uint64 total_cycle = 0;         // 積算実行サイクル数
                    269:        int32 cycle_cache = 0;          // キャッシュケースの所用サイクル数
                    270:        int32 cycle_nocache = 0;        // ノーキャッシュケースの時の *追加分*
                    271:        uint64 inst_count = 0;          // 命令実行数
                    272: 
                    273:        // ブランチ履歴
                    274:        // 1エントリは64ビット。上位32ビットがブランチ先アドレス、下位32ビットが
                    275:        // ブランチ元命令のアドレス。
                    276:        // brhist_top がカーソル(次に書き込む位置)を示しており8ビットなので勝手に
                    277:        // 循環する。.count = 0 は書き込み前の無効エントリ。
                    278:        // 16バイト単位のテーブルなので16バイト境界に整列がよかろう。
                    279:        alignas(16) m68kbrhist brhist[256] {};
                    280:        // 直近に使用したインデックスを指す。
                    281:        // ループ回数カウントのため、次に書き込むインデックスでないことに注意。
                    282:        uint8 brhist_top = 0;
                    283: 
                    284:        // バス
                    285:        m68kbus bus {};
                    286: 
                    287:        // 手抜きのためリセットベクタ取得アドレスを知っている。
                    288:        // リセット時のためだけにデバイス側に細工を入れるのは実行時の
                    289:        // オーバーヘッドが大きそうなので。
                    290:        uint32 reset_vector = 0;
                    291: 
                    292:        // A-Line, F-Line 命令エミュレーションのコールバックとユーザ引数。
                    293:        // ユーザ引数には関与しないので呼び出し側が自由に指定してよい。
                    294:        // コールバック側で処理完了したら true を返す。
                    295:        // デフォルトの処理(すなわちm68k例外)にする場合は false を返す。
                    296:        bool (*aline_callback)(m68kcpu *, void *) = NULL;
                    297:        void *aline_arg = NULL;
                    298:        bool (*fline_callback)(m68kcpu *, void *) = NULL;
                    299:        void *fline_arg = NULL;
                    300: };
                    301: 
                    302: #define RegD(n)                (cpu->reg.da[(n)])
                    303: #define RegA(n)                (cpu->reg.da[(n) + 8])
                    304: #define RegR(n)                (cpu->reg.da[(n)])
                    305: #define RegPC                  (cpu->reg.pc)
                    306: #define RegPPC                 (cpu->ppc)
                    307: #define RegIR                  (cpu->ir)
                    308: #define RegIR2                 (cpu->ir2)
                    309: #define RegSR                  (cpu->reg.sr_h() | cpu->reg.ccr.Get())
                    310: #define RegVBR                 (cpu->reg.vbr)
                    311: #define RegUSP                 (cpu->reg.usp)
                    312: #define RegISP                 (cpu->reg.isp)
                    313: #define RegMSP                 (cpu->reg.msp)
                    314: #define RegSFC                 (cpu->reg.sfc)
                    315: #define RegDFC                 (cpu->reg.dfc)
                    316: #define RegCACR                (cpu->reg.cacr)
                    317: #define RegCAAR                (cpu->reg.caar)
                    318: 
                    319: #define RegFP(n)       (cpu->reg.fpframe.fpf_regs[n])
                    320: #define RegFPCR                (cpu->reg.fpframe.fpf_fpcr)
                    321: #define RegFPSR                (cpu->reg.fpframe.fpf_fpsr)
                    322: #define RegFPIAR       (cpu->reg.fpframe.fpf_fpiar)
                    323: 
                    324: #define RegIRX                 ((RegIR >> 9) & 7)
                    325: #define RegIRY                 (RegIR & 7)
                    326: #define RegDX                  RegD(RegIRX)
                    327: #define RegAX                  RegA(RegIRX)
                    328: #define RegDY                  RegD(RegIRY)
                    329: #define RegAY                  RegA(RegIRY)
                    330: 
                    331: // 外部公開ルーチン
                    332: extern m68kcpu *m68030_init(uint32 reset_vector);
                    333: extern uint32 m68030_run(m68kcpu *cpu, uint64 request);
                    334: extern void m68030_exception_reset(m68kcpu *cpu);
                    335: extern void m68030_interrupt(m68kcpu *cpu, int level, int vector);
                    336: 
                    337: // 外部で定義されるコールバック
                    338: extern void m68030_reset_inst(m68kcpu *cpu);

unix.superglobalmegacorp.com

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