📄 run.cc
字号:
#include "koala.hh"// Koala correctly simulates the intricate details of the R4600/R4700 five// stage pipeline. Each iteration of the loop completely executes the// instruction from the W pipeline stage in that Pclock cycle. This highly// simplifies accurate simulation of the pipeline.//// - Exceptions (which abort all following instructions and slip) can be// processed as slips, as we haven't attempted to process the aborted// instructions yet.//// - Pipeline slips (including exceptions) are handled simply by incrementing// the clock by the number of slip cycles.//// - Stalls are more complicated, in that the already-processed instruction// are delayed. This is normally not a problem, as these instructions are// still guranteed to complete, unless the instructions access external timing// data such as Random or an interrupt source. WARNING: currently, I ignore// this subtle difference and treat all stalls as slips.//// Originally, I was using C++ exceptions to simulate MIPS interrupts and// exceptions. However, this is somewhat messy and inefficient (although in// theory it shouldn't be), so I've switched to longjmp() instead. Also, in// order to accurately simulate interrupt priorities, asynchronous events// (interrupts, NMI, soft reset and cold reset) are signalled directly by// setting the corresponding bit of (events). As ironic as handling// synchronous exceptions asynchronously and asynchronous interrupts// synchronously sounds, it works well.#include <stdio.h>voidKoala::run(ClockValue timeslice){ setjmp(env); for (;;) { // Reset gpr[0]. gpr[0] = 0; // First of all, increment the PClock counter. After this, all we need // to handle is any slips and stalls. ++now; poll(); // Check for interrupts. In read hardware, these have a priority lower // than all exceptions, but simulating this effect is too hard to be // worth the effort (interrupts and resets are not meant to be // delivered accurately anyway.) if (events) { if (bits(events, 7, 0)) process_reset(); else if (bit(cp0[SR], SR_IE) && !bit(cp0[SR], SR_EXL) && !bit(cp0[SR], SR_ERL) && (events & cp0[SR])) process_interrupt(); } // Look up the ITLB. It's not clear from the manuals whether the ITLB // stores the ASIDs or not. I assume it does. ITLB has the same size // as in the real hardware, mapping two 4KB pages. Because decoding a // MIPS64 virtual address is far from trivial, ITLB and DTLB actually // improve the simulator's performance: something I cannot say about // caches and JTLB. PA pa; VA vpn = pc / 4096; if (vpn == itlb[0].vpn && asid_match(asid, itlb[0].asid)) { pa = itlb[0].pa + (pc % 4096); lru_itlb = 1; } else if (vpn == itlb[1].vpn && asid_match(asid, itlb[1].asid)) { pa = itlb[1].pa + (pc % 4096); lru_itlb = 0; } else { // Do a full address translation. This introduces a slip in the I // pipeline stage. The slip costs 1 cycle for branch, jump and // ERET instructions, and 2 cycles otherwise. ++now; pa = translate_vaddr(pc, instr_fetch); itlb[lru_itlb].vpn = vpn; itlb[lru_itlb].asid = asid; itlb[lru_itlb].pa = round_down(pa, 4096); lru_itlb = !lru_itlb; } // Access the instruction cache. Because the simulated caches are // slow, we maintain a two-entry buffer to cut down full fetches by // the factor of (up to) sixteen. Instr instr; if (ibuf_match(pc, ibuf[0].tag)) { instr = swizzle<word>(ibuf[0][pc], pc); lru_ibuf = 1; } else if (ibuf_match(pc, ibuf[1].tag)) { instr = swizzle<word>(ibuf[1][pc], pc); lru_ibuf = 0; } else { // No such luck: fetch the data from the cache. instr = fetch(pc, pa); } // Now, we can decode and execute the instruction. int next_state = decode(instr); // Dump the registers if required. if (trace_level >= dump_gprs) dump_gpr_registers(); // Advance the PC. switch (pipeline) { case nothing_special: pc += 4; break; case branch_delay: pc = branch_target; break; case instr_addr_error: process_address_error(instr_fetch, branch_target); } pipeline = next_state; }}voidKoala::dump_gpr_registers() const{ log("\tpc = %016lx sr = %016lx", pc, cp0[SR]); for (int i = 0; i < 32; i += 2) { log("\t%s = %016lx %s = %016lx", regname[i], gpr[i], regname[i + 1], gpr[i + 1]); }}voidKoala::dump_state(){ size_t i; msg("Registers:"); msg("\tpc = %016lx sr = %016lx", pc, cp0[SR]); for (int i = 0; i < 32; i += 2) { msg("\t%s = %016lx %s = %016lx", regname[i], gpr[i], regname[i + 1], gpr[i + 1]); } msg("TLB:"); for (i = 0; i < tlb_size; i++) msg("\thi = %016lx lo0 = %08x lo1 = %08x", tlb[i].hi, tlb[i].lo[0], tlb[i].lo[1]);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -