📄 interp.c
字号:
int uncached; if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached, isTARGET, isREAL)) { const uword64 mask = 0x7; const unsigned int reverse = ReverseEndian ? 1 : 0; const unsigned int bigend = BigEndianCPU ? 1 : 0; uword64 memval; unsigned int byte; paddr = (paddr & ~mask) | ((paddr & mask) ^ (reverse << 2)); LoadMemory (&memval,NULL,uncached, AccessLength_WORD, paddr, vaddr, isDATA, isREAL); byte = (vaddr & mask) ^ (bigend << 2); return EXTEND32 (memval >> (8 * byte)); } } return 0;}/* Simulate the mips16 entry and exit pseudo-instructions. These would normally be handled by the reserved instruction exception code, but for ease of simulation we just handle them directly. */static voidmips16_entry (SIM_DESC sd, sim_cpu *cpu, address_word cia, unsigned int insn){ int aregs, sregs, rreg;#ifdef DEBUG printf("DBG: mips16_entry: entered (insn = 0x%08X)\n",insn);#endif /* DEBUG */ aregs = (insn & 0x700) >> 8; sregs = (insn & 0x0c0) >> 6; rreg = (insn & 0x020) >> 5; /* This should be checked by the caller. */ if (sregs == 3) abort (); if (aregs < 5) { int i; signed_word tsp; /* This is the entry pseudo-instruction. */ for (i = 0; i < aregs; i++) store_word (SD, CPU, cia, (uword64) (SP + 4 * i), GPR[i + 4]); tsp = SP; SP -= 32; if (rreg) { tsp -= 4; store_word (SD, CPU, cia, (uword64) tsp, RA); } for (i = 0; i < sregs; i++) { tsp -= 4; store_word (SD, CPU, cia, (uword64) tsp, GPR[16 + i]); } } else { int i; signed_word tsp; /* This is the exit pseudo-instruction. */ tsp = SP + 32; if (rreg) { tsp -= 4; RA = load_word (SD, CPU, cia, (uword64) tsp); } for (i = 0; i < sregs; i++) { tsp -= 4; GPR[i + 16] = load_word (SD, CPU, cia, (uword64) tsp); } SP += 32; if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT) { if (aregs == 5) { FGR[0] = WORD64LO (GPR[4]); FPR_STATE[0] = fmt_uninterpreted; } else if (aregs == 6) { FGR[0] = WORD64LO (GPR[5]); FGR[1] = WORD64LO (GPR[4]); FPR_STATE[0] = fmt_uninterpreted; FPR_STATE[1] = fmt_uninterpreted; } } PC = RA; } }/*-- trace support ----------------------------------------------------------*//* The TRACE support is provided (if required) in the memory accessing routines. Since we are also providing the architecture specific features, the architecture simulation code can also deal with notifying the TRACE world of cache flushes, etc. Similarly we do not need to provide profiling support in the simulator engine, since we can sample in the instruction fetch control loop. By defining the TRACE manifest, we add tracing as a run-time option. */#if defined(TRACE)/* Tracing by default produces "din" format (as required by dineroIII). Each line of such a trace file *MUST* have a din label and address field. The rest of the line is ignored, so comments can be included if desired. The first field is the label which must be one of the following values: 0 read data 1 write data 2 instruction fetch 3 escape record (treated as unknown access type) 4 escape record (causes cache flush) The address field is a 32bit (lower-case) hexadecimal address value. The address should *NOT* be preceded by "0x". The size of the memory transfer is not important when dealing with cache lines (as long as no more than a cache line can be transferred in a single operation :-), however more information could be given following the dineroIII requirement to allow more complete memory and cache simulators to provide better results. i.e. the University of Pisa has a cache simulator that can also take bus size and speed as (variable) inputs to calculate complete system performance (a much more useful ability when trying to construct an end product, rather than a processor). They currently have an ARM version of their tool called ChARM. */voiddotrace (SIM_DESC sd, sim_cpu *cpu, FILE *tracefh, int type, SIM_ADDR address, int width, char *comment,...){ if (STATE & simTRACE) { va_list ap; fprintf(tracefh,"%d %s ; width %d ; ", type, pr_addr(address), width); va_start(ap,comment); vfprintf(tracefh,comment,ap); va_end(ap); fprintf(tracefh,"\n"); } /* NOTE: Since the "din" format will only accept 32bit addresses, and we may be generating 64bit ones, we should put the hi-32bits of the address into the comment field. */ /* TODO: Provide a buffer for the trace lines. We can then avoid performing writes until the buffer is filled, or the file is being closed. */ /* NOTE: We could consider adding a comment field to the "din" file produced using type 3 markers (unknown access). This would then allow information about the program that the "din" is for, and the MIPs world that was being simulated, to be placed into the trace file. */ return;}#endif /* TRACE *//*---------------------------------------------------------------------------*//*-- simulator engine -------------------------------------------------------*//*---------------------------------------------------------------------------*/static voidColdReset (SIM_DESC sd){ int cpu_nr; for (cpu_nr = 0; cpu_nr < sim_engine_nr_cpus (sd); cpu_nr++) { sim_cpu *cpu = STATE_CPU (sd, cpu_nr); /* RESET: Fixed PC address: */ PC = (unsigned_word) UNSIGNED64 (0xFFFFFFFFBFC00000); /* The reset vector address is in the unmapped, uncached memory space. */ SR &= ~(status_SR | status_TS | status_RP); SR |= (status_ERL | status_BEV); /* Cheat and allow access to the complete register set immediately */ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT && WITH_TARGET_WORD_BITSIZE == 64) SR |= status_FR; /* 64bit registers */ /* Ensure that any instructions with pending register updates are cleared: */ PENDING_INVALIDATE(); /* Initialise the FPU registers to the unknown state */ if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT) { int rn; for (rn = 0; (rn < 32); rn++) FPR_STATE[rn] = fmt_uninterpreted; } }}/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) *//* Signal an exception condition. This will result in an exception that aborts the instruction. The instruction operation pseudocode will never see a return from this function call. */voidsignal_exception (SIM_DESC sd, sim_cpu *cpu, address_word cia, int exception,...){ /* int vector; */#ifdef DEBUG sim_io_printf(sd,"DBG: SignalException(%d) PC = 0x%s\n",exception,pr_addr(cia));#endif /* DEBUG */ /* Ensure that any active atomic read/modify/write operation will fail: */ LLBIT = 0; /* Save registers before interrupt dispatching */#ifdef SIM_CPU_EXCEPTION_TRIGGER SIM_CPU_EXCEPTION_TRIGGER(sd, cpu, cia);#endif switch (exception) { case DebugBreakPoint: if (! (Debug & Debug_DM)) { if (INDELAYSLOT()) { CANCELDELAYSLOT(); Debug |= Debug_DBD; /* signaled from within in delay slot */ DEPC = cia - 4; /* reference the branch instruction */ } else { Debug &= ~Debug_DBD; /* not signaled from within a delay slot */ DEPC = cia; } Debug |= Debug_DM; /* in debugging mode */ Debug |= Debug_DBp; /* raising a DBp exception */ PC = 0xBFC00200; sim_engine_restart (SD, CPU, NULL, NULL_CIA); } break; case ReservedInstruction: { va_list ap; unsigned int instruction; va_start(ap,exception); instruction = va_arg(ap,unsigned int); va_end(ap); /* Provide simple monitor support using ReservedInstruction exceptions. The following code simulates the fixed vector entry points into the IDT monitor by causing a simulator trap, performing the monitor operation, and returning to the address held in the $ra register (standard PCS return address). This means we only need to pre-load the vector space with suitable instruction values. For systems were actual trap instructions are used, we would not need to perform this magic. */ if ((instruction & RSVD_INSTRUCTION_MASK) == RSVD_INSTRUCTION) { int reason = (instruction >> RSVD_INSTRUCTION_ARG_SHIFT) & RSVD_INSTRUCTION_ARG_MASK; if (!sim_monitor (SD, CPU, cia, reason)) sim_io_error (sd, "sim_monitor: unhandled reason = %d, pc = 0x%s\n", reason, pr_addr (cia)); /* NOTE: This assumes that a branch-and-link style instruction was used to enter the vector (which is the case with the current IDT monitor). */ sim_engine_restart (SD, CPU, NULL, RA); } /* Look for the mips16 entry and exit instructions, and simulate a handler for them. */ else if ((cia & 1) != 0 && (instruction & 0xf81f) == 0xe809 && (instruction & 0x0c0) != 0x0c0) { mips16_entry (SD, CPU, cia, instruction); sim_engine_restart (sd, NULL, NULL, NULL_CIA); } /* else fall through to normal exception processing */ sim_io_eprintf(sd,"ReservedInstruction at PC = 0x%s\n", pr_addr (cia)); } default: /* Store exception code into current exception id variable (used by exit code): */ /* TODO: If not simulating exceptions then stop the simulator execution. At the moment we always stop the simulation. */#ifdef SUBTARGET_R3900 /* update interrupt-related registers */ /* insert exception code in bits 6:2 */ CAUSE = LSMASKED32(CAUSE, 31, 7) | LSINSERTED32(exception, 6, 2); /* shift IE/KU history bits left */ SR = LSMASKED32(SR, 31, 4) | LSINSERTED32(LSEXTRACTED32(SR, 3, 0), 5, 2); if (STATE & simDELAYSLOT) { STATE &= ~simDELAYSLOT; CAUSE |= cause_BD; EPC = (cia - 4); /* reference the branch instruction */ } else EPC = cia; if (SR & status_BEV) PC = (signed)0xBFC00000 + 0x180; else PC = (signed)0x80000000 + 0x080;#else /* See figure 5-17 for an outline of the code below */ if (! (SR & status_EXL)) { CAUSE = (exception << 2); if (STATE & simDELAYSLOT) { STATE &= ~simDELAYSLOT; CAUSE |= cause_BD; EPC = (cia - 4); /* reference the branch instruction */ } else EPC = cia; /* FIXME: TLB et.al. */ /* vector = 0x180; */ } else { CAUSE = (exception << 2); /* vector = 0x180; */ } SR |= status_EXL; /* Store exception code into current exception id variable (used by exit code): */ if (SR & status_BEV) PC = (signed)0xBFC00200 + 0x180; else PC = (signed)0x80000000 + 0x180;#endif switch ((CAUSE >> 2) & 0x1F) { case Interrupt: /* Interrupts arrive during event processing, no need to restart */ return; case NMIReset: /* Ditto */#ifdef SUBTARGET_3900 /* Exception vector: BEV=0 BFC00000 / BEF=1 BFC00000 */ PC = (signed)0xBFC00000;#endif /* SUBTARGET_3900 */ return; case TLBModification: case TLBLoad: case TLBStore: case AddressLoad: case AddressStore: case InstructionFetch: case DataReference: /* The following is so that the simulator will continue from the exception handler address. */ sim_engine_halt (SD, CPU, NULL, PC, sim_stopped, SIM_SIGBUS); case ReservedInstruction: case CoProcessorUnusable: PC = EPC; sim_engine_halt (SD, CPU, NULL, PC, sim_stopped, SIM_SIGILL); case IntegerOverflow: case FPE: sim_engine_halt (SD, CPU, NULL, PC, sim_stopped, SIM_SIGFPE); case BreakPoint: sim_engine_halt (SD, CPU, NULL, PC, sim_stopped, SIM_SIGTRAP); break; case SystemCall: case Trap: sim_engine_restart (SD, CPU, NULL, PC); break; case Watch: PC = EPC; sim_engine_halt (SD, CPU, NULL, PC, sim_stopped, SIM_SIGTRAP); default: /* Unknown internal exception */ PC = EPC; sim_engine_halt (SD, CPU, NULL, PC, sim_stopped, SIM_SIGABRT); } case SimulatorFault: { va_list ap; char *msg; va_start(ap,exception); msg = va_arg(ap,char *); va_end(ap); sim_engine_abort (SD, CPU, NULL_CIA, "FATAL: Simulator error \"%s\"\n",msg); } } return;}/* This function implements what the MIPS32 and MIPS64 ISAs define as "UNPREDICTABLE" behaviour. About UNPREDICTABLE behaviour they say: "UNPREDICTABLE results may vary from processor implementation to processor implementation, instruction to instruction, or as a function of time on the same implementation or instruction. Software can never depend on results that are UNPREDICTABLE. ..." (MIPS64 Architecture for Programmers Volume II, The MIPS64 Instruction Set. MIPS Document MD00087 revision 0.95, page 2.) For UNPREDICTABLE behaviour, we print a message, if possible print the offending instructions mips.igen instruction name (provided by the caller), and stop the simulator.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -