📄 ms_fetch.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_fetch.c - Handle instruction fetching for the MXS simulator * * Jim Bennett * 1994, 1995 */#ifdef MIPSY_MXS#include <sys/types.h>#endif#include <stdlib.h>#include "ms.h"#ifdef MIPSY_MXS#include "cpu_state.h"#include "mipsy.h"#include "annotations.h"#include "cp0.h"#include "pcache.h"#endif/* Global variable set if there is an annotation on this instruction. */extern int mxs_annotation;static int ms_rename (struct s_cpu_state *st, INST *ip, THREAD *th, int this_inst, int store_inst); /* * ms_fetch - Fetch instructions from the text segment and add * them to the instruction window */void ms_fetch (struct s_cpu_state *st) { INST *ip; THREAD *th; BrTREE *br; int this_inst, fetches, store_inst; int nfetch; /* Number of successful fetches */#ifdef MIPSY_MXS uint inst;#endif AddToStat (ST_FETCHES_TRIED, FETCH_WIDTH); if (st->exception_pending) { /* Pending exception stalls all threads */ AddToStat (ST_FETCH_EXPEND, FETCH_WIDTH) return; } nfetch = 0;#if MAX_ACT_THREADS == 1 for (fetches=0;fetches<FETCH_WIDTH;fetches++)#else for (th = st->active_thread, fetches=0; fetches<FETCH_WIDTH; fetches++, th = th->active_thread)#endif { /* If instruction window is full, */ /* then proceed to next unit. */ if (st->iwin_ninst >= IWIN_SIZE) { AddToStat (ST_FETCH_IW_FULL, FETCH_WIDTH-fetches) break; } this_inst = st->iwin_nextfree; if (this_inst < 0) { AddToStat (ST_FETCH_RB_FULL, FETCH_WIDTH-fetches) break; } /* If there are no active unstalled threads, */ /* then proceed to next unit. */#if MAX_ACT_THREADS == 1 th = st->active_thread; if (!th) { AddToStat (ST_FETCH_STALL_OTH,FETCH_WIDTH-fetches) AddToStat (ST_FETCH_STALL,FETCH_WIDTH-fetches) break; } if (th->stall_fetch) { if (th->stall_branch) { if (th->stall_thread) { AddToStat (ST_FETCH_STALLTHREAD,FETCH_WIDTH-fetches); } else { AddToStat (ST_FETCH_STALLBRANCH,FETCH_WIDTH-fetches); } } else if (th->stall_fpc) { AddToStat (ST_FETCH_STALLFPC,FETCH_WIDTH-fetches); } else if (th->stall_icache) { AddToStat (ST_FETCH_STALLICACHE,FETCH_WIDTH-fetches); } else if (th->stall_itlbmiss) { AddToStat (ST_FETCH_STALLITLB,FETCH_WIDTH-fetches); } else if (th->stall_except) { AddToStat (ST_FETCH_STALLEXCEPT,FETCH_WIDTH-fetches); } else if (th->stall_sys) { AddToStat (ST_FETCH_STALLSYS,FETCH_WIDTH-fetches); } else if (th->stall_cp0) { AddToStat (ST_FETCH_STALLCP0,FETCH_WIDTH-fetches); } else if (th->stall_sc) { AddToStat (ST_FETCH_STALLSC,FETCH_WIDTH-fetches); } else { AddToStat (ST_FETCH_STALL_OTH,FETCH_WIDTH-fetches); } AddToStat (ST_FETCH_STALL,FETCH_WIDTH-fetches)#ifndef MIPSY_MXS#ifdef DEBUG_CHECKS if (((th->thread_st & TH_SPEC) == 0) && (th->stall_icache || th->stall_except) ) { fprintf (stderr, "Fetch unit permanently stalled\r\n"); fprintf (stderr, "Cycle #% 9d%0.5d\r\n", st->work_ticks, st->work_cycle); ms_break (st, NULL, "ERR"); }#endif#endif break; }#else while ((th) && th->stall_fetch) th = th->active_thread; if (th == NULL) { th = st->active_thread; while ((th) && th->stall_fetch) th = th->active_thread; if (th == NULL) { AddToStat (ST_FETCH_STALL_OTH, FETCH_WIDTH-fetches) AddToStat (ST_FETCH_STALL, FETCH_WIDTH-fetches); break; } }#endif ip = &st->iwin [this_inst];#ifdef MIPSY_MXS /* Fetch the instruction to this thread */ { PA paddr; int ret, dum1, dum2, bdoor; uint tlbFlavor = TLB_IFETCH|TLB_READING; CPUState *P = (CPUState *) (st->mipsyPtr); if ((th->pc & 3) == 0) { void *bdoorAddr = 0; ret = TranslateVirtual(P, th->pc, &paddr, &tlbFlavor, &bdoorAddr); } else { RECORD_EXCEPTION(P, EXC_RADE, E_VEC,th->pc, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]); ret = FAILURE; } if (ret != SUCCESS) { th->except = GetLastException(st); th->stall_itlbmiss = 1; UpdateStallFetch (th); IncStat (ST_FETCH_STALLITLB); IncStat (ST_FETCH_STALL); continue; } bdoor = (tlbFlavor & TLB_BDOOR); if (!bdoor) { st->ms_action = ACT_UNSTALL_ICACHE; P->PC = th->pc; ret = ReadICache(P->myNum, th->pc, paddr, &inst); if (ret != SUCCESS) { if (ret == FAILURE) { /* Cache wouldn't accept req - stall for a cycle. */ IncStat (ST_FETCH_CACHEFAILURE); IncStat (ST_FETCH_STALLICACHE); IncStat (ST_FETCH_STALL); continue; } th->stall_icache = 1; th->icache_stall_reason = MxsClassifyMiss(P->myNum, th->pc, paddr, TRUE); UpdateStallFetch (th); IncStat (ST_FETCH_STALLICACHE); IncStat (ST_FETCH_STALL); continue; } } if (!bdoor) { compile_inst (inst, th->pc, ip, &dum1, &dum2); } else { ip->op = OPBDOOR; ip->r1 = ip->r2 = ip->r3 = -1; ip->imm = paddr; } }#else /* If the PC of this thread is invalid, then */ /* stall the thread. */ if (th->pc == OUTSIDE_ADDR) { th->stall_icache = 1; UpdateStallFetch (th); IncStat (ST_FETCH_STALL_INV); IncStat (ST_FETCH_STALL); continue; } /* Fetch the instruction to this thread */ *ip = pmap.ctbuf[th->pc];#endif#ifdef PRINT_INST { int t, flagp; if (enable_iprint && ((st->work_cycle % iprint_frequency) == 0)) { printf ("% 7d%0.5d @0x%8.8x: ", st->work_ticks, st->work_cycle, th->debugpc); print_inst (stdout, ip); flagp = 0; if (ip->r2 > 0) { t = th->regnames [ip->r2]; printf (" ["); print_reg_contents (stdout, ip->r2, &st->regs[t]); flagp = 1; } if (ip->r3 > 0) { t = th->regnames [ip->r3]; if (flagp) printf (", "); else printf (" ["); print_reg_contents (stdout, ip->r3, &st->regs[t]); flagp = 1; } if (flagp) printf ("]\r\n"); else printf ("\r\n");#ifdef PRINT_IREG for (i=0; i<32; i+=8) printf ( "%8x %8x %8x %8x %8x %8x %8x %8x\r\n", Ireg(i), Ireg(i+1), Ireg(i+2), Ireg(i+3), Ireg(i+4), Ireg(i+5), Ireg(i+6), Ireg(i+7)); printf ("\r\n");#endif } }#endif st->iwin_br_node [this_inst] = th->branch_node;#ifdef BREAKPOINT if (th->debugpc == brkpt) ms_break (st, ip, "PC BRK"); if (ip->op == opcbrk) ms_break (st, ip, "OP BRK");#endif /* If it is a branch likely inst, we need to */ /* ensure we can process it now. */ /* NOTE: This means that branch likely inst's */ /* won't work in a non-speculative model. */ /* I.e. THREAD_WIDTH must be at least two. */ if (is_likely (ip->op) && (st->nthreads >= THREAD_WIDTH)) { IncStat (ST_FETCH_THREAD); continue; } /* Convert illegal instruction sequence to */ /* illegal instruction, for exception handling */ if (th->branch_dly && (is_branch (ip->op) || is_call (ip->op))) { ip->op = OPILL; ip->r1 = ip->r2 = ip->r3 = -1; } /* Rename logical registers to use real */ /* (physical) registers. */ store_inst = is_store (ip->op); if (ms_rename (st, ip, th, this_inst, store_inst) < 0) { IncStat (ST_FETCH_NAME); continue; } /* Rename succeeded, so it is OK to update the */ /* machine state now. */ ms_grad_enqueue (st, this_inst); st->iwin_pc [this_inst] = th->pc; st->iwin_flags [this_inst] |= IWIN_BUSY; if (mxs_annotation) st->iwin_flags [this_inst] |= IWIN_ANNOTATED; if (th->thread_st & TH_SPEC) st->iwin_flags [this_inst] |= IWIN_SPEC; st->iwin_nextfree = st->iwin_freelist [this_inst]; th->pc = th->pc + PC_INC; th->debugpc += 4; /* Add instruction to list for this thread */ br = &st->branch_tree [th->branch_node]; if (br->iwin_tail_th >= 0) { st->iwin_thread [br->iwin_tail_th] = this_inst; st->iwin_bthread [this_inst] = br->iwin_tail_th; st->iwin_thread [this_inst] = -1; br->iwin_tail_th = this_inst; } else { br->iwin_head_th = this_inst; br->iwin_tail_th = this_inst; st->iwin_bthread [this_inst] = -1; st->iwin_thread [this_inst] = -1; } /* Add load/store instructions to load/store chain */ if (is_ldst (ip->op)) { if (store_inst) st->iwin_flags [this_inst] |= IWIN_STORE; ms_ldst_enqueue (st, this_inst);#ifdef ONE_PHASE_LS /* Loads and stores must wait if there is a */ /* preceeding store. */ if (st->iwin_nstores > 0) st->iwin_flags [this_inst] |= IWIN_LDST_DEP; /* A store must wait if there are any */ /* preceeding loads or stores. */ if (store_inst) { if (this_inst != st->iwin_head_ldst) st->iwin_flags [this_inst] |= IWIN_LDST_DEP; st->iwin_nstores++; }#endif } /* Add this instruction to the tail */ /* of the priority chain in the window */ nfetch++; ms_pri_enqueue (st, this_inst); /* If we've just fetched some kind of branch, */ /* then stop fetching until the branch is */ /* resolved. */ if (is_branch (ip->op) || is_call (ip->op)) { if (th->branch_dly) { fprintf (stderr, "No branches allowed in branch shadow!!\r\n"); ms_break (st, NULL, "ERR"); } /* IWIN_BRDLY is used to hold off issue */ /* of this inst until branch delay */ /* slots have been fetched. */ st->iwin_flags [this_inst] |= IWIN_BRDLY + IWIN_BRANCH; th->branch_inum = this_inst; th->branch_dly = BRANCH_SLOTS + 1; th->returnpc = th->pc + (BRANCH_SLOTS*PC_INC); /* Handle branch likely instructions */ if (is_likely (ip->op)) { th->stall_branch = 1; UpdateStallFetch (th); ms_branch (st, th, 1); } } else /* If it is a system call or a write to the FP */ /* control register, stall fetching until all */ /* prior instructions are executed. */ if (is_sys (ip->op) || is_fp_ctl (ip->op) || is_sc(ip->op)) { if (is_sc (ip->op)) th->stall_sc = 1; else if (is_sys(ip->op)) { if (ip->op == OPCP0) th->stall_cp0 = 1; else th->stall_sys = 1; } else th->stall_fpc = 1; UpdateStallFetch (th); if (!is_sc(ip->op))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -