Annotation of nono/m88xx0/m88100.h, revision 1.1.1.6

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: 
                      7: #pragma once
                      8: 
                      9: #include "header.h"
1.1.1.2   root       10: #include "branchhistory.h"
1.1       root       11: #include "bus.h"
1.1.1.2   root       12: #include "m88200.h"
1.1       root       13: #include <atomic>
                     14: 
                     15: // 外部リクエストフラグ
                     16: // XXX m680x0 側にもよく似たものがあってどうしたもんか
1.1.1.2   root       17: #define CPU_REQ_STOP           (0x00000001)    // ストップ状態
1.1       root       18: #define CPU_REQ_TRACE          (0x00000004)    // デバッガ有効
                     19: #define CPU_REQ_PROMPT         (0x00000008)    // デバッガプロンプト
                     20: #define CPU_REQ_RELEASE                (0x00000010)    // 命令後に CPU 実行中断
                     21: #define CPU_REQ_INTR           (0x00000020)    // 命令後に割り込みチェック
1.1.1.5   root       22: #define CPU_REQ_RESET          (0x00000040)    // リセット例外
1.1       root       23: 
                     24: // m88100 レジスタイメージを保持する構造体。
                     25: // この構造体はコピーや比較をするので、ポインタとかは置かないこと。
                     26: struct m88100reg
                     27: {
                     28:        // PID(cr0)
                     29:        static const uint32 PID_REV_MASK        = 0x0000ff00; // 0 = MC88100
                     30:        static const uint32 PID_VER_MASK        = 0x000000fe;
                     31:        static const uint32 PID_MASTER          = 0x00000001;
                     32:        // PSR(cr1)
                     33:        static const uint32 PSR_SUPER           = 0x80000000;
                     34:        static const uint32 PSR_BO_LE           = 0x40000000; // ByteOrder(Little)
                     35:        static const uint32 PSR_SER                     = 0x20000000;
                     36:        static const uint32 PSR_C                       = 0x10000000; // Carry
                     37:        static const uint32 PSR_SFD1            = 0x00000008; // SFU1 Disable
                     38:        static const uint32 PSR_MXM                     = 0x00000004; // MisalignedAccessEnable
                     39:        static const uint32 PSR_IND                     = 0x00000002; // Interrupt Disable
                     40:        static const uint32 PSR_SFRZ            = 0x00000001; // Shadow Freeze
                     41: 
                     42:        // 例外処理で使用される S*IP
                     43:        static const uint32 SIP_MASK            = 0xfffffffcU;
                     44:        static const uint32 SIP_V                       = 0x00000002;
                     45:        static const uint32 SIP_E                       = 0x00000001;
                     46: 
                     47:        // DMTn、データ例外
                     48:        static const uint32 DM_BO                       = 0x00008000;
                     49:        static const uint32 DM_DAS                      = 0x00004000;
                     50:        static const uint32 DM_DOUB1            = 0x00002000;
                     51:        static const uint32 DM_LOCK                     = 0x00001000;
                     52:        static const uint32 DM_DREG_MASK        = 0x00000f80;
                     53:        static const uint32 DM_SIGNED           = 0x00000040;
                     54:        static const uint32 DM_EN3                      = 0x00000020;
                     55:        static const uint32 DM_EN2                      = 0x00000010;
                     56:        static const uint32 DM_EN1                      = 0x00000008;
                     57:        static const uint32 DM_EN0                      = 0x00000004;
                     58:        static const uint32 DM_EN_MASK          = (DM_EN0 | DM_EN1 | DM_EN2 | DM_EN3);
                     59:        static const uint32 DM_WRITE            = 0x00000002;
                     60:        static const uint32 DM_VALID            = 0x00000001;
                     61:        // 内部識別フラグ
                     62:        static const uint32 DM_SIZE_B           = (1U << 16) | DM_EN3;
                     63:        static const uint32 DM_SIZE_H           = (1U << 17) | DM_EN3 | DM_EN2;
                     64:        static const uint32 DM_SIZE_W           = (1U << 18) | DM_EN_MASK;
                     65:        static const uint32 DM_USR                      = (1U << 20);
                     66:        static const uint32 DM_BU                       = DM_SIZE_B;
                     67:        static const uint32 DM_B                        = DM_SIZE_B | DM_SIGNED;
                     68:        static const uint32 DM_HU                       = DM_SIZE_H;
                     69:        static const uint32 DM_H                        = DM_SIZE_H | DM_SIGNED;
                     70:        static const uint32 DM_W                        = DM_SIZE_W;
                     71:        static const uint32 DM_D1                       = DM_SIZE_W | DM_DOUB1;
                     72:        static const uint32 DM_D2                       = DM_SIZE_W;
                     73: 
                     74:        // 頻繁にアクセスしそうな変数はオフセットの若いほうに持ってきておく。
                     75: 
                     76:        // 実行中の命令
                     77:        uint64 opX = 0;
                     78:        // プリフェッチ命令
                     79:        uint64 opF = 0;
                     80: 
                     81:        uint32 xip = 0;
                     82:        uint32 nip = 0;
                     83:        uint32 fip = 0;
                     84: 
                     85:        uint32 r[32] {};
                     86:        union {
                     87:                uint32 cr[21] {};
                     88:                struct {
                     89:                        uint32 pid;             // cr0
                     90:                        uint32 psr;             // cr1
                     91:                        uint32 epsr;    // cr2
                     92:                        uint32 ssbr;    // cr3
                     93:                        uint32 sxip;    // cr4
                     94:                        uint32 snip;    // cr5
                     95:                        uint32 sfip;    // cr6
                     96:                        uint32 vbr;             // cr7
                     97:                        uint32 dmt0;    // cr8
                     98:                        uint32 dmd0;    // cr9
                     99:                        uint32 dma0;    // cr10
                    100:                        uint32 dmt1;    // cr11
                    101:                        uint32 dmd1;    // cr12
                    102:                        uint32 dma1;    // cr13
                    103:                        uint32 dmt2;    // cr14
                    104:                        uint32 dmd2;    // cr15
                    105:                        uint32 dma2;    // cr16
                    106:                        uint32 sr[4];   // cr17,18,19,20
                    107:                };
                    108:        };
                    109:        union {
                    110:                uint32 fcr[11] {};
                    111:                struct {
                    112:                        uint32 fpecr;   // fcr0
                    113:                        uint32 fphs1;   // fcr1
                    114:                        uint32 fpls1;   // fcr2
                    115:                        uint32 fphs2;   // fcr3
                    116:                        uint32 fpls2;   // fcr4
                    117:                        uint32 fppt;    // fcr5
                    118:                        uint32 fprh;    // fcr6
                    119:                        uint32 fprl;    // fcr7
                    120:                        uint32 fpit;    // fcr8
                    121:                        uint32 fpsr;    // fcr62 [9]
                    122:                        uint32 fpcr;    // fcr63 [10]
                    123:                };
                    124:        };
                    125: 
                    126:        // 直近のデータアクセスアドレス
                    127:        uint32 lastaddr;
                    128: 
                    129:        // スーパーバイザ/ユーザモードなら true
                    130:        bool IsSuper()  const { return (psr & PSR_SUPER) != 0; }
                    131:        bool IsUser()   const { return (psr & PSR_SUPER) == 0; }
                    132: 
1.1.1.5   root      133:        // 割り込みが許可なら true
                    134:        bool IsIntrEnable() const { return (psr & PSR_IND) == 0; }
                    135: 
1.1.1.4   root      136:        // SFU1(FPU)が有効なら true
                    137:        bool IsFPUEnable() const        { return (psr & PSR_SFD1) == 0; }
                    138: 
1.1       root      139:        // MXM (Misaligned Access Enable) なら true
                    140:        bool IsMXM()    const { return (psr & PSR_MXM) != 0; }
                    141: 
                    142:        // キャリーフラグが立っていれば 1 を返す
                    143:        uint32 GetCY() const { return (psr >> 28) & 1; }
1.1.1.4   root      144: 
                    145:        // キャリーフラグをセットする。
                    146:        // cy のうち最下位ビットのみ参照する (呼び出し側はマスクせず渡してよい)
1.1       root      147:        void SetCY(uint cy) {
                    148:                psr &= ~PSR_C;
                    149:                psr |= ((cy & 1) << 28);
                    150:        }
                    151: 
                    152:        static const char * const sipname[3];
1.1.1.2   root      153:        static const char * const dmt_en_str[16];
1.1       root      154: };
                    155: 
                    156: class m88kcpu : public m88100reg
                    157: {
1.1.1.4   root      158:        static const uint64 DELAYSLOT = 1ULL << 62;
                    159: 
                    160:        enum ExceptionKind
                    161:        {
                    162:                NORMAL,
                    163:                DATA,
                    164:                ERROR,
                    165:                INTR,
                    166:                TRAP,
                    167:        };
                    168: 
1.1       root      169:  public:
1.1.1.5   root      170:        m88kcpu(uint32 reset_vector_);
1.1       root      171:        virtual ~m88kcpu();
                    172: 
1.1.1.5   root      173:        uint32 Run(uint32 delta);
1.1       root      174:        void Release();
1.1.1.5   root      175:        void RequestReset();
                    176: 
                    177:        // 仮想時刻を返す
1.1.1.6 ! root      178:        uint64 GetVTime() const { return total_vtime + Cycle2Vtime(used_cycle); }
1.1       root      179: 
1.1.1.5   root      180:        // 割り込み信号線が変化したことの通知を受ける。
                    181:        // level は 0 か 1。
                    182:        void Interrupt(int level);
1.1       root      183: 
1.1.1.2   root      184:        // PID.VERSION を設定する (初期化時に呼ぶ)
                    185:        void SetVersion(uint32 version);
                    186: 
1.1.1.4   root      187:        // クラス外部からの xip 取得
                    188:        uint32 GetXIP() const   { return xip; }
1.1       root      189: 
                    190:        // op が>=0ならバスエラーは起きていない
                    191:        //  そのときに DELAYSLOT bit が 0 ならば通常
                    192:        //  bit32 が 1 ならば遅延スロット命令
                    193:        // op が負数ならバスエラーが起きた
                    194:        //  そのときに DELAYSLOT bit が 1 ならば通常バスエラー
                    195:        //  bit32 が 0 ならば遅延スロットでのバスエラー
                    196:        // バスエラーかどうかのチェックのほうが回数が多いため、
                    197:        // バスエラー優先にしたい。
                    198: 
1.1.1.4   root      199:        static bool OpIsBusErr(uint64 op) {
1.1       root      200:                return (int64)op < 0;
                    201:        }
1.1.1.4   root      202: 
                    203:        // op が DelaySlot 実行なら true を返す。デバッガで表示用に使う。
                    204:        static bool OpIsDelay(uint64 op) {
1.1       root      205:                return (OpIsBusErr(op) ? ~op : op) & DELAYSLOT;
                    206:        }
                    207: 
1.1.1.4   root      208:        // サイクルを加算 (m88200 から使う)
1.1.1.5   root      209:        // 今は単純に加算しているだけでオーバーラップなどは考慮してない
                    210:        void AddCycle(int32 wait) { used_cycle += wait; }
                    211: 
                    212:        // MPU クロックを設定
                    213:        void SetClockSpeed(uint32 clock_khz_) { clock_khz = clock_khz_; }
1.1.1.4   root      214: 
                    215:        std::atomic<uint32> atomic_reqflag {}; // リクエストフラグ
                    216: 
                    217:        // [0] 命令バス
                    218:        // [1] データバス
                    219:        m88200 cmmu[2] {};
                    220: 
                    221:        // ブランチ履歴 (例外履歴を含む)
                    222:        BranchHistory_m88xx0 brhist {};
                    223:        // 例外履歴のみ
                    224:        BranchHistory_m88xx0 exhist {};
                    225: 
1.1.1.5   root      226:        // 32bit 命令コードからディスパッチ用の 12bit に変換。
                    227:        static uint32 op32_to_12(uint32 op) {
                    228:                return ((op >> 20) & 0x0fc0) | ((op >> 10) & 0x003f);
                    229:        }
                    230: 
1.1.1.4   root      231:        // 例外名を返す
                    232:        static const char *GetExceptionName(int vector);
                    233: 
                    234:  private:
1.1.1.5   root      235:        void Reset();
                    236: 
1.1.1.4   root      237:        uint64 fetch() {
                    238:                nip = fip;
                    239:                opF = cmmu[0].load_32(fip);
                    240:                fip += 4;
                    241:                return opF;
                    242:        }
                    243: 
                    244:        // PSR を newpsr に変更する。
1.1.1.2   root      245:        // CY ビットは特別にこの関数を経由しないで変更してよいことにする。
                    246:        void SetPSR(uint32 newpsr)
                    247:        {
                    248:                psr = newpsr;
1.1.1.4   root      249:                SetPSR();
                    250:        }
                    251:        // 更新された psr に基づいて、PSR 変更によって必要な処理をする。
                    252:        // CY ビットを変更した場合は呼ばなくてよいことにする。
                    253:        void SetPSR()
                    254:        {
1.1.1.2   root      255:                // CMMU に S/U 信号を出す
                    256:                cmmu[0].SetSuper(IsSuper());
                    257:                cmmu[1].SetSuper(IsSuper());
1.1.1.5   root      258:                // 割り込み許可なら割り込みチェック
                    259:                if (IsIntrEnable()) {
                    260:                        atomic_reqflag |= CPU_REQ_INTR;
                    261:                }
1.1.1.2   root      262:        }
                    263: 
1.1       root      264:        void Exception(int vec);
                    265:        void ExceptionCore(int vec, ExceptionKind cause);
1.1.1.5   root      266:        uint32 Calcdmt(uint32 flag);
                    267:        void ReadDataException32(uint32 addr, uint32 flag);
                    268:        void ReadDataException64(uint32 addr, uint32 flag);
                    269:        void WriteDataException32(uint32 addr, uint32 flag);
                    270:        void WriteDataException64(uint32 addr, uint32 flag);
                    271:        void XmemDataException(uint32 addr, uint32 flag);
                    272:        void FPException(int fpex);
1.1.1.2   root      273: 
1.1       root      274:        // ブランチ処理用
1.1.1.4   root      275:        void EnterBranch(uint32 toaddr);
1.1       root      276:        void ExitBranch();
                    277:        void ExitDelayBranch();
1.1.1.2   root      278:        uint32 nop_counter {};  // STOP 検出用の nop 命令カウンタ
                    279: 
1.1       root      280:        // ロードストア命令用の下処理
1.1.1.2   root      281:        bool ldst_usr(uint32& usr);
1.1       root      282:        uint32 ldst_scale(uint32 size);
                    283:        bool ldst_align(uint32 size, uint32& addr);
                    284: 
                    285: #define OP_PROTO(name) void __CONCAT(op_,name)()
                    286: #include "m88100ops.h"
1.1.1.2   root      287: OP_PROTO(illegal);
1.1       root      288: #undef OP_PROTO
                    289: 
                    290:        void op_unimpl() {
                    291:                printf("unimplemented op XIP=%08x opX=%08x\n", xip, (uint32)opX);
                    292:        }
1.1.1.4   root      293:        void fpu_unimpl();
                    294: 
1.1.1.5   root      295:        // 仮想時刻 [nsec]
                    296:        uint64 total_vtime {};
                    297: 
                    298:        // サイクル数を仮想時間 [nsec] に変換
                    299:        uint64 Cycle2Vtime(int32 cycle) const {
                    300:                return (int64)cycle * 1000 * 1000 / clock_khz;
1.1.1.4   root      301:        }
                    302: 
1.1.1.5   root      303:        // 仮想時間 [nsec] をサイクル数に変換
                    304:        uint32 Vtime2Cycle(uint32 vtime) const {
                    305:                return (uint32)((uint64)vtime * clock_khz / (1000 * 1000));
                    306:        }
                    307: 
                    308:        // 今のところサイクルを正確に実装するのは無理なので
                    309:        // 適当に全部積み上げてある。
                    310:        uint32 used_cycle {};           // 現在のターンでこれまでに消費したサイクル数
                    311:        uint32 goal_cycle {};           // 現在のターンで消費すべきサイクル数
                    312:        uint32 clock_khz {};            // MPU クロック [kHz]
                    313: 
                    314:        // ペンディング中の割り込みレベル
                    315:        int intr_pending {};
                    316: 
                    317:        // リセットベクタ
                    318:        uint32 reset_vector {};
1.1.1.3   root      319: 
                    320:        // 例外名
                    321:        static const char * const exception_names[];
1.1       root      322: };

unix.superglobalmegacorp.com

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