📄 koala.hh
字号:
#ifndef koala_hh_included#define koala_hh_included#include <setjmp.h>#include <mips64/bus.hh>#include <mips64/cache.hh>#include <mips64/cpu.hh>#include <mips64/types.hh>#include <checkpoint.hh>#include <clock.hh>#include <cpu.hh>#include <inttypes.hh>#include <serial.hh>class Koala : public virtual Serializable, public MIPS64Cpu{ private: static SerialType<Koala> type;public: // The usual interfaces. Koala(const SimArgs& args); Koala(Checkpoint& cp); ~Koala(); void reset(bool warm); void checkpoint(Checkpoint& cp, bool parent = false) const; // The fetch-execute loop. void run(ClockValue timeslice); // Interrupt delivery functions: void deliver_cold_reset(); void deliver_soft_reset(); void deliver_nmi(); void deliver_interrupt(unsigned int n); void clear_interrupt(unsigned int n); void dump_state();public: // Register names, for debugging. static const char* regname[32]; // 16 bit implementation and revision fields. The upper 8 bits are 0x20 // for R4600, 0x21 for R4700. The lower 8 bits should distinguish the // simulator. static const UInt32 ImpRev = 0x2070; // A system coprocessor timer interrupt. class Timer : public Event, public virtual Serializable { private: static SerialType<Timer> type; Koala* cpu; public: Timer(Koala* c, ClockValue w) : Event(w, 0), cpu(c) { } explicit Timer(const SimArgs& args) : Event(args) { assert(UNREACHABLE); } explicit Timer(Checkpoint& cp); void invoke(); void checkpoint(Checkpoint& cp, bool parent = false) const; }; // Fundamental parameters. static const int vaddr_width = 40; static const int log2_icache_assoc = 1; static const int log2_icache_size = 14; static const int log2_icache_line = 5; static const int log2_dcache_assoc = 1; static const int log2_dcache_size = 14; static const int log2_dcache_line = 5; static const size_t write_buffers = 0; static const size_t tlb_size = 48; static const VA xkseg_end = VA(C000,00FF,8000,0000); // Some instruction latencies. These are for R4600. On R4700, both all // four multiplication latencies are decreased by four cycles. static const int mult_latency = 10; static const int multu_latency = 10; static const int div_latency = 42; static const int divu_latency = 42; static const int dmult_latency = 12; static const int dmultu_latency = 12; static const int ddiv_latency = 74; static const int ddivu_latency = 74; // Asynchronous event constants. Each interrupt source corresponds to a // single bit of the (events) word. Bits 8 through 16 correspond to // interrupts 0 through 7. Other bits represent the three reset exceptions // as follows: enum { cold_reset_event = 1 << 0, soft_reset_event = 1 << 1, nmi_event = 1 << 2 }; // Cache of some strategic CPU mode bits. This shortcut is used to avoid // parsing of the somewhat convoluted Status register during address // translation and instruction decoding. enum { xmode = 1 << 0, // 64 bit mode ([USK]X & [usk]mode) cmode = 1 << 1, // 32 bit (compatibility) mode (!xmode) bmode = 1 << 2, // big-endian-cpu (big_endian_mem() ^ reverse_endian()) rmode = 1 << 3, // reverse-endian (RE && umode) umode = 1 << 4, // user mode smode = 1 << 5, // supervisor mode kmode = 1 << 6 // kernel mode }; // Pipeline information. This is fairly ad hoc, but it is still useful. enum { nothing_special, // nothing special branch_delay, // current instruction in the branch-delay slot instr_addr_error // instruction address error }; // A TLB Entry structure. struct TLBEntry { TLBEntry* next; // the hash chain TLBEntry* prev; // the hash chain UInt64 hi; // VPN/2 << 13 UInt64 mask; // ~((oddbit << 1) - 1) UInt64 oddbit; // the odd bit of VPN UInt32 lo[2]; // EntryLo0/1 Int16 asid; // the ASID, sign bit set for global entries. UInt16 index; // TLB index UInt16 hash; // TLB map index }; // An invalid ASID bit used to mark unused TLB entries. static const Int16 invalid_asid = (1 << 8); // An global ASID bit. static const Int16 global_asid = (Int16)(1 << 15); // Geometry of the TLB lookup map (see below.) static const int log2_tlb_map_size = 8; static const int tlb_map_size = 1 << log2_tlb_map_size; // Cache structures. See <mips64/cache.hh> for details. typedef MIPS64Cache<log2_icache_size,log2_icache_line,log2_icache_assoc> ICache; typedef MIPS64Cache<log2_dcache_size,log2_dcache_line,log2_dcache_assoc> DCache; // An invalid cache tag used to mark unused cache lines. static const UInt32 bad_tag = ~UInt32(0); // An invalid ibuf tag used to marked unused icache buffers. static const VA bad_ibuf_tag = ~(VA)(0); // An invalid physical address returned by translate_vaddr() on cache // operations that specify an invalid address. static const PA bad_pa = ~PA(0); // TLB access types, used to select the appropriate TLB miss handler. enum { instr_fetch, // instruction fetch data_load, // data load data_store, // data store cache_op // cache operations (ignore errors) }; // The two-entry ITLB. Each entry maps a 4KB page. struct ITLBEntry { VA vpn; // virtual address page number (va / 4KB) PA pa; // physical address and the caching algorithm Int16 asid; // ASID and the global bit. }; // Although not in real hardware, we also cache the two most recent // I-cache accesses, as simulating cache lookups is slow, and as many as 8 // instructions can be fetched from one cache line. struct ICacheBuffer { VA tag; // address of the cache shifted by log2_icache_line UInt64* line; // pointer to the ICache line. // Extract a doubleword given a PC. UInt64 operator[] (VA pc) const { return line[bits(pc, Koala::log2_icache_line - 1, 3)]; } }; // CPU state. Int16 asid; // same as the ASID field in EntryHi UInt16 events; // external events: this also replaces Cause[15:8]. UInt8 pipeline; // current instruction in the branch-delay slot UInt8 mode; // CPU mode bool sync_bit; // true after executing the SYNC instruction. VA branch_target; // next PC when in the branch delay slot // cp0[Random] is not updated on each clock cycle. Instead, its value is // updated when either cp0[Random] or cp0[Wired] is set, and the current // value is computed using the time elapsed since then. ClockValue random_seed; // Similary, we lazily compute the value of the Count register. ClockValue count_seed; // ITLB data. (lru_itlb) stores the index of the least-recently used entry. ITLBEntry itlb[2]; bool lru_itlb; // I-cache buffer data (lru_ibuf) stores the index of the least-recently // used entry (0 or 1). ICacheBuffer ibuf[2]; bool lru_ibuf; // There's at most one timer interrupt pending at any given time. Timer* timer; // The longjmp buffer used for handling exceptions. jmp_buf env; // The TLB and L1 caches. TLBEntry tlb[tlb_size]; ICache icache; DCache dcache; // The TLB map used to simulate the direct-mapped TLB lookup. There's an // extra entry at the end that contains the hash chain of all unused TLB // entries (that way, there is always exactly (tlb_size) mappings in the // hash table). TLBEntry* tlb_map[tlb_map_size + 1]; // The trace mode flag. enum { no_tracing, report_interrupts, report_exceptions, print_instructions, dump_gprs }; // The NOP guard. static const UInt32 catch_nops = 128; size_t nop_count; // (mode) operations. void enter_kernel_mode() { mode = kmode | (bit(cp0[SR], SR_KX) ? xmode : cmode); if (big_endian_mem()) mode |= bmode; } void leave_kernel_mode() { switch (bits(cp0[SR], SR_KSU_Last, SR_EXL) << 1) { case 1 << SR_KSU_Last: // user mode = umode | (bit(cp0[SR], SR_UX) ? xmode : cmode); if (bit(cp0[SR], SR_RE)) mode |= rmode; if (big_endian_mem() != bool(reverse_endian())) mode |= bmode; break; case 1 << SR_KSU_First: // supervisor mode = smode | (bit(cp0[SR], SR_SX) ? xmode : cmode); if (big_endian_mem()) mode |= bmode; break; default: // kernel (or undefined, but I ignore that bit ;) mode = kmode | (bit(cp0[SR], SR_KX) ? xmode : cmode); if (big_endian_mem()) mode |= bmode; break; } } // Compute the current value of the Random register. int get_random() const {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -