📄 ms_grad.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * */ /* * ms_grad.c - Handle instruction graduation for the MXS simulator * * Only needed to implement precise interrupts * Also handles exceptions for the MIPSY version of MXS * * Jim Bennett * 1994, 1995 */#ifdef MIPSY_MXS#include <sys/types.h>#endif#include "ms.h"#ifdef MIPSY_MXS#include "mipsy.h"#include "cpu_state.h"#include "cpu_interface.h"#include "cp0.h"#include "hw_events.h"#include "machine_defs.h"#endif#define COHERENCY_EXCEPTION -1#define SWITCH2MIPSY_EXCEPTION -2static void RecordExceptionStats(struct s_cpu_state *st);static int InstIsInterruptable(struct s_cpu_state *st); /* * ms_graduate - Graduate instructions at the tail of the * graduation queue that have been freed. * * This routine maintains the state of the processor at * the graduation point, which is the only point at which * consistency is assured. */void ms_graduate (struct s_cpu_state *st) {#ifdef PRECISE int inum, flush_inst; int i; THREAD *th; INST *ip; int lreg, halfreg; AddToStat (ST_GRADS_TRIED, GRAD_WIDTH); if (st->exception_pending) { AddToStat (ST_GRAD_EXPEND, GRAD_WIDTH); record_pipeline_stall(st, st->grad.pc,GRAD_WIDTH); return; } th = &st->grad; for (i=0; i<GRAD_WIDTH; i++) { inum = st->iwin_headgrad; if ((inum >= 0) && ((st->iwin_flags[inum] & IWIN_FREED) || ((st->iwin_flags[inum] & IWIN_FAULT) && !(st->iwin_flags[inum] & IWIN_SPEC)))) { if (st->iwin_br_node [inum] == 0) {#ifdef BANREMOVE if ((th->pc != st->iwin_pc[inum]) && (th->pc < SIMBASEADDR)) { ms_break(st, NULL, "pc error"); }#endif /* If the instruction at the head of the graduation */ /* queue caused an exception, then bail out now. */ if (st->iwin_flags[inum] & IWIN_FAULT) { st->exception_pending = 1; st->except = st->iwin_except [inum]; AddToStat (ST_GRAD_EXPEND, GRAD_WIDTH-i); record_pipeline_stall(st, th->pc,GRAD_WIDTH-i); return; } /* Retire stores out of the store buffer, if we can, */ /* bail out if we can't. */ if (st->iwin_flags[inum] & IWIN_LDST) { if (st->iwin_flags[inum] & IWIN_LDSTBUF) { int ret = ldst_buffer_retire(st,inum); if (ret != 0) { /* Line hasn't come back to cache - try again later */ if (ret > 0) { if (st->iwin_flags[inum] & IWIN_STORE) { AddToStat (ST_GRAD_STSTALL, GRAD_WIDTH-i); } else { AddToStat (ST_GRAD_LDSTALL, GRAD_WIDTH-i); } record_ldst_stall(st, inum, GRAD_WIDTH-i); return; } /* Line was nuked from the cache - backup and retry */ st->exception_pending = 1; st->except = COHERENCY_EXCEPTION; AddToStat (ST_GRAD_EXPEND, GRAD_WIDTH-i); record_pipeline_stall(st, th->pc,GRAD_WIDTH-i); return; } } flush_inst = (st->iwin_flags[inum] & IWIN_FLUSH); IncStat(ST_GRAD_INST_LDST); if (is_sc(st->iwin[inum].op)) { THREAD *sth = &st->threads[st->branch_tree[0].thread]; /* Continue the instruction fetcher after an SC */ sth->stall_sc = 0; UpdateStallFetch (sth); } } else { flush_inst = (st->iwin_flags[inum] & IWIN_FLUSH); } if (st->iwin_flags[inum] & IWIN_ANNOTATED) {#ifdef MIPSY_MXS int cpuNum = ((CPUState *) (st->mipsyPtr))->myNum;#if 0 /* * Make sure to check the instruction sampling before * executing the annotation. */ if (PE[cpuNum].numInstructions >= PE[cpuNum].nextInstrSample) { INST_SAMPLE_EVENT(MipsyReadTime(cpuNum), cpuNum, PE[cpuNum].PC); PE[cpuNum].nextInstrSample += MS_SAMPLE_INSTR_INTERVAL; }#endif #ifdef NOTDEF if(IS_KUSEG(st->iwin_pc[inum])) { PE[cpuNum].lastUserAnnotation = st->iwin_pc[inum]; } AnnExec(AnnFMLookup(st->iwin_pc[inum], ANNFM_PC_TYPE));#endif#endif /* MIPSY_MXS */ st->iwin_flags[inum] &= ~IWIN_ANNOTATED; } /* if (st->iwin_pc[inum] == 0x80004294) { int foo = 1; CPUWarning("LOOPING"); while (foo) ; } */ /* We've got an instruction that is all done, so */ /* graduate it. */ if (th->thread_st & TH_BRANCH) { th->pc = th->branch_pc; th->thread_st &= ~TH_BRANCH; } else th->pc = th->pc + PC_INC; if (st->iwin_flags[inum] & IWIN_BRANCH) { if (is_likely(st->iwin[inum].op) && !(st->iwin_flags[inum] & IWIN_TAKENBR)) { /* The next PC of a not taken branch likely * instruction skips over the delay slot. */ th->pc = st->iwin_branch_pc[inum]; } else { /* Regular branches update after delay slot inst */ th->thread_st |= TH_BRANCH; th->branch_pc = st->iwin_branch_pc [inum]; } }#ifndef R3K if ((st->iwin[inum].op == OPCP0) && (st->iwin[inum].imm == 0x42000018)) { /* R4K eret doesn't have a delay slot either. */ th->pc = st->iwin_branch_pc[inum]; }#endif IncStat(ST_GRAD_INST);#ifdef MIPSY_MXS {#ifdef BANREMOVE CPUState *P = (CPUState *)(st->mipsyPtr); P->numInstructions++; if (P->numInstructions > P->nextInstrSample) { INST_SAMPLE_EVENT(MipsyReadTime(P->myNum), P->myNum, P->PC); P->nextInstrSample += MS_SAMPLE_INSTR_INTERVAL; }#endif } RunPCAnnotations(st->iwin_pc[inum], 0);#endif /* MIPSY_MXS */ /* Have to dequeue before updating the register name */ /* table, so that old name of register can be released */ ms_grad_dequeue (st, inum); /* The thread state at the graduation point needs to */ /* correctly track the register name table. This code */ /* duplicates the actions that the fetch unit took when */ /* this instruction was fetched. */ ip = &st->iwin[inum]; if ((lreg = st->iwin_lr2[inum]) > 0) th->half_def[lreg >> 1] = 0; if ((lreg = st->iwin_lr3[inum]) > 0) th->half_def[lreg >> 1] = 0; if ((lreg = st->iwin_lr1 [inum]) > 0) { halfreg = lreg >> 1; if ((lreg < FPREG) || (lreg >= MAX_FP)) th->regnames [lreg] = ip->r1; else if ((lreg < FPCTL) || (lreg >= TOT_REG)) { if ((ip->op == OPCVTDW) || (ip->op == OPCVTDS) || ((ip->op >= OPFADDD) && (ip->op <= OPFFLOORD))) { th->regnames[lreg] = ip->r1; th->regnames[lreg+1] = ip->r1 + 1; th->half_def[halfreg] = 0; } else { if (th->half_def[halfreg] == (lreg^0x01)) th->half_def[halfreg] = 0; else { int dest_reg, evenreg; dest_reg = ip->r1 & (~0x01); evenreg = halfreg << 1; th->half_def[halfreg] = lreg; th->regnames[evenreg] = dest_reg; th->regnames[evenreg+1] = dest_reg+1; } } } } /* CPUPrint("PC %#llx\n", st->iwin_pc[inum]); */ /* AnnExec(AnnFMLookup(st->iwin_pc[inum], ANNFM_PC_TYPE)); */ } else { /* If it's completed, delete it regardless of which */ /* branch node it is on. */ if (st->iwin_flags[inum] & IWIN_LDST) {#ifdef DEBUG_CHECKS if (st->iwin_flags[inum] & IWIN_LDSTBUF) { fprintf (stderr, "Squashed entry still in ldst buf\n"); ms_break (st, NULL, "ERR"); }#endif IncStat(ST_GRAD_SQUASHED_LDST); } IncStat(ST_GRAD_SQUASHED); flush_inst = 0; ms_grad_dequeue (st, inum); record_pipeline_stall(st, th->pc,1); } continue; /* Keep on graduating instructions, */ } /* since this one graduated. */ if (inum < 0) { /* Pipeline is totally empty */ if (st->active_thread && st->active_thread->stall_icache) { /* Nothing done this cycle - record this as memory stall */ record_icache_stall(st, th->pc,GRAD_WIDTH-i); AddToStat(ST_GRAD_ICACHESTALL, GRAD_WIDTH-i); } else if (flush_inst) { record_pipeline_stall(st, th->pc,GRAD_WIDTH-i); AddToStat(ST_GRAD_FLUSHSTALL, GRAD_WIDTH-i); } else { record_pipeline_stall(st, th->pc,GRAD_WIDTH-i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -