ms_fetch.c
来自「一个用在mips体系结构中的操作系统」· C语言 代码 · 共 830 行 · 第 1/2 页
C
830 行
st->iwin_flags [this_inst] |= IWIN_FLUSH; } /* If there is branch processing in progress */ /* for this thread, check if we have finished */ /* fetching the branch delay instructions. */ /* If so, then OK to process the branch. */ /* In the case of the branch likely, the branch */ /* has already been processed, so just update */ /* the PC to the branch target. */ if (th->branch_dly) { th->branch_dly--; if (th->branch_dly == 0) { if (th->branch_likely) { th->pc = th->branch_likely_pc; th->branch_likely = 0; } else { th->stall_branch = 1; UpdateStallFetch (th); ms_branch (st, th, 0); } } } CheckInstAvail (st, this_inst); if (ip->op == OPILL) { /* Current off the fetching for threads that encounter an * illegal instruction. */ th->stall_except = 1; UpdateStallFetch (th); } } AddToStat (ST_FETCHES, nfetch); } /* * ms_rename - Rename logical registers to use real (physical) * registers. Note that register 0 is never remapped, * and that registers are allocated in pairs. * * Returns -1 if rename fails (out of free registers, or * special register still in use) * * If a source register has the REG_ERROR bit set, this indicates * that the writer of the register caused a fault, so stall * this thread until the problem is dealt with. */static int ms_rename (struct s_cpu_state *st, INST *ip, THREAD *th, int this_inst, int store_inst) { int lreg_ix, reg_ix, dest_reg; REGSTAT *rs; int old_reg_ix, old_lreg, old_half_def; int halfreg, evenreg, preg, halfpreg; int owner;#ifdef PRECISE st->iwin_lr1 [this_inst] = ip->r1; st->iwin_lr2 [this_inst] = ip->r2; st->iwin_lr3 [this_inst] = ip->r3;#endif if (ip->r2 > 0) { lreg_ix = ip->r2 >> 1; if (lreg_ix != (ip->r1 >> 1)) th->half_def[lreg_ix] &= ~REGNAME_MASK; ip->r2 = th->regnames [ip->r2]; reg_ix = ip->r2 >> 1; if (st->reg_rstat[reg_ix].reg_status & REG_ERROR) { th->stall_except = 1; UpdateStallFetch (th); IncStat (ST_REG_ERROR); return (-1); } } if (ip->r3 > 0) { lreg_ix = ip->r3 >> 1; if (lreg_ix != (ip->r1 >> 1)) th->half_def[lreg_ix] &= ~REGNAME_MASK; ip->r3 = th->regnames [ip->r3]; reg_ix = ip->r3 >> 1; if (st->reg_rstat[reg_ix].reg_status & REG_ERROR) { th->stall_except = 1; UpdateStallFetch (th); IncStat (ST_REG_ERROR); return (-1); } } /* For destination register renaming, need a */ /* new register name. Find a free register, */ /* set owner to be this instruction, and set */ /* status = mapped + busy + in window. */ old_reg_ix = -1; if (ip->r1 > 0) { reg_ix = st->reg_nextfree; if (reg_ix < 0) { IncStat (ST_REG_BUSY); return (-1); /* Out of free reg's */ } dest_reg = reg_ix << 1; halfreg = ip->r1 >> 1;/************************************************************************* At this point, the fetch is guaranteed to complete except for the case of a special register, or a double precision register that has been claimed by another thread, which might still be in use. In the other cases, it is safe to update the machine state.*************************************************************************/ /* Handle integer reg renaming */ if ((ip->r1 < FPREG) || (ip->r1 >= MAX_FP)) { old_reg_ix = th->regnames[ip->r1] >> 1; old_lreg = ip->r1; old_half_def = 0; th->regnames[ip->r1] = dest_reg; AcquireRegMap (&st->reg_rstat[reg_ix], th, ip->r1); st->reg_owner [dest_reg] = this_inst; st->reg_rstat[reg_ix].reg_status |= REG_BUSY + REG_IN_WIN; st->reg_excuse [reg_ix] = ST_NOT_ISSUED; st->new_excuse [reg_ix] = ST_NOT_ISSUED; st->reg_nextfree = st->reg_freelist [reg_ix]; st->iwin_flags [this_inst] |= IWIN_DEFINE;#ifdef BREAKPOINT if (ip->r1 == trace_reg) trace_preg = dest_reg;#endif ip->r1 = dest_reg; } else /* Handle FP reg renaming, keep */ /* track of odd/even register */ /* pairs. */ if ((ip->r1 < FPCTL) || (ip->r1 >= TOT_REG)) { if ((ip->op == OPCVTDW) || (ip->op == OPCVTDS) || ((ip->op >= OPFADDD) && (ip->op <= OPFFLOORD)) ) { /* These instructions update both */ /* halves of an FP register pair. */ old_reg_ix = th->regnames[ip->r1] >> 1; old_lreg = ip->r1; old_half_def = th->half_def[halfreg]; th->regnames[ip->r1] = dest_reg; th->regnames[ip->r1+1] = dest_reg+1; th->half_def[halfreg] = 0; AcquireRegMap (&st->reg_rstat[reg_ix], th, ip->r1); st->reg_owner [dest_reg] = this_inst; st->reg_owner [dest_reg+1] = this_inst; st->reg_rstat[reg_ix].reg_status |= REG_BUSY + REG_IN_WIN; st->reg_excuse [reg_ix] = ST_NOT_ISSUED; st->new_excuse [reg_ix] = ST_NOT_ISSUED; st->reg_nextfree = st->reg_freelist [reg_ix]; st->iwin_flags [this_inst] |= IWIN_DEFINE;#ifdef BREAKPOINT if (ip->r1 == trace_reg) trace_preg = dest_reg;#endif ip->r1 = dest_reg; } else { /* Otherwise, are updating a half pair */ int old_owner; evenreg = halfreg << 1; halfpreg = (th->regnames[evenreg]) >> 1; if ((th->half_def[halfreg]) && ((th->half_def[halfreg] & REGNAME_MASK) == (ip->r1^0x01)) ) { /* Check if another thread has claimed */ /* this register, and if not then stake */ /* our claim. */ rs = &st->reg_rstat[halfpreg]; if (rs->reg_status & REG_CLAIMED) { IncStat (ST_REG_CLAIMED); return (-1); } rs->reg_status |= REG_CLAIMED; rs->reg_nclaims = 1; /* If there is a danger that this register */ /* might be referenced by a non-descendant */ /* thread, set the control flag, so that the */ /* write won't complete until the instruction */ /* is no longer speculative. */ preg = th->regnames[ip->r1]; old_owner = st->reg_owner [preg]; if (((rs->reg_status & REG_IN_WIN) == 0) || (st->iwin_br_node [old_owner] != th->branch_node)) st->iwin_flags [this_inst] |= IWIN_CTL; /* The first half of the register def */ /* is still valid, so complete the def */ th->half_def[halfreg] |= REGNAME_CLAIM; th->half_def[halfreg] &= ~REGNAME_MASK; st->reg_owner [preg] = this_inst;#ifdef BREAKPOINT if (ip->r1 == trace_reg) trace_preg = preg;#endif ip->r1 = preg; /* If it is still in the window, set */ /* register doubly mapped, and point */ /* from first definition to this one. */ if (rs->reg_status & REG_IN_WIN) { rs->reg_status |= REG_DMAP; st->reg_otherhalf2 [halfpreg] = -1; if ((preg & (~0x01)) == (ip->r2 & (~0x01))) st->reg_otherhalf2 [halfpreg] = this_inst; st->reg_otherhalf3 [halfpreg] = -1; if ((preg & (~0x01)) == (ip->r3 & (~0x01))) st->reg_otherhalf3 [halfpreg] = this_inst; } else { /* If the other half is no longer around, then */ /* set this instruction as the register owner. */ st->reg_owner [preg ^ 0x01] = this_inst; rs->reg_status |= REG_BUSY + REG_IN_WIN; st->reg_excuse [halfpreg] = ST_NOT_ISSUED; st->new_excuse [halfpreg] = ST_NOT_ISSUED; } } else { /* Otherwise, treat this as the start */ /* of a new (half) definition. */ old_reg_ix = th->regnames[evenreg] >> 1; old_lreg = evenreg; old_half_def = th->half_def[halfreg]; th->half_def[halfreg] = ip->r1; th->regnames[evenreg] = dest_reg; th->regnames[evenreg+1]= dest_reg+1; st->regs[dest_reg] = 0; st->regs[dest_reg+1] = 0; AcquireRegMap (&st->reg_rstat[reg_ix], th, ip->r1); st->reg_owner [dest_reg] = this_inst; if (ip->r1 & 0x01) { dest_reg++; st->reg_owner [dest_reg] = this_inst; } st->reg_rstat[reg_ix].reg_status |= REG_BUSY + REG_IN_WIN; st->reg_excuse [reg_ix] = ST_NOT_ISSUED; st->new_excuse [reg_ix] = ST_NOT_ISSUED; st->reg_nextfree = st->reg_freelist [reg_ix]; st->iwin_flags [this_inst] |= IWIN_DEFINE;#ifdef BREAKPOINT if (ip->r1 == trace_reg) trace_preg = dest_reg;#endif ip->r1 = dest_reg; } } } else /* For special registers, keep new */ /* writer out until the previous */ /* instance is out of the system. */ { evenreg = halfreg << 1; preg = th->regnames[evenreg]; halfpreg = preg >> 1; if (st->reg_rstat[halfpreg].reg_status & REG_BUSY) { IncStat (ST_REG_SPEC); return (-1); } st->iwin_flags [this_inst] |= IWIN_CTL; st->reg_owner [preg] = this_inst; if (ip->r1 & 0x01) st->reg_owner [preg+1] = this_inst; st->reg_rstat[halfpreg].reg_status |= REG_BUSY + REG_IN_WIN; st->reg_excuse [halfpreg] = ST_NOT_ISSUED; st->new_excuse [halfpreg] = ST_NOT_ISSUED; ip->r1 = (ip->r1 & 0x01 ? preg+1 : preg); } }/**************************************************************************** Except as noted above, updates to machine state should occur after this point. Previously, the fetch could be aborted. Now we know the fetch succeeds, so we can update the machine state accordingly.****************************************************************************/ /* During renaming, check for dependency on previous */ /* instruction in window, increment reference count, */ /* and add this inst to dependency list. */ halfpreg = ip->r1 >> 1; if (ip->r2 > 0) { reg_ix = ip->r2 >> 1; rs = &st->reg_rstat [reg_ix]; rs->reg_ref++;#ifdef DEBUG_CHECKS if (!(rs->reg_status & (REG_BUSY | REG_MAPPED))) ms_break (st, ip, "CONERR");#endif if (rs->reg_status & REG_IN_WIN) { if (reg_ix == halfpreg) { if (rs->reg_status & REG_DMAP) { st->iwin_flags [this_inst] |= IWIN_DEP2; owner = st->reg_owner [ip->r1 ^ 0x01]; st->iwin_dep2 [owner] [st->iwin_index2[owner]++] = this_inst; } } else { st->iwin_flags [this_inst] |= IWIN_DEP2; owner = st->reg_owner [reg_ix << 1]; st->iwin_dep2 [owner] [st->iwin_index2[owner]++] = this_inst; } } } if (ip->r3 > 0) { reg_ix = ip->r3 >> 1; rs = &st->reg_rstat [reg_ix]; rs->reg_ref++;#ifdef DEBUG_CHECKS if (!(rs->reg_status & (REG_BUSY | REG_MAPPED))) ms_break (st, ip, "CONERR");#endif#ifdef ONE_PHASE_LS if (rs->reg_status & REG_IN_WIN)#else /* For stores, don't worry about R3, the load */ /* store buffer will handle that. */ if ((rs->reg_status & REG_IN_WIN) && (!store_inst))#endif { if (reg_ix == halfpreg) { if (rs->reg_status & REG_DMAP) { st->iwin_flags [this_inst] |= IWIN_DEP3; owner = st->reg_owner [ip->r1 ^ 0x01]; st->iwin_dep3 [owner] [st->iwin_index3[owner]++] = this_inst; } } else { st->iwin_flags [this_inst] |= IWIN_DEP3; owner = st->reg_owner [reg_ix << 1]; st->iwin_dep3 [owner] [st->iwin_index3[owner]++] = this_inst; } } } if (old_reg_ix >= 0) { int sav_half_def; sav_half_def = th->half_def[old_lreg>>1]; th->half_def[old_lreg>>1] = old_half_def; ReleaseRegMap (st, th, old_reg_ix, old_lreg); th->half_def[old_lreg>>1] = sav_half_def; } return (0); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?