📄 ms.c
字号:
/* reg and see if it is now free. */ rs->reg_status &= ~REG_IN_WIN; STX->reg_excuse[reg_ix] = ST_NO_EXCUSE; STX->new_excuse[reg_ix] = ST_NO_EXCUSE; CheckRegFree (STX, rs, reg_ix); /* Turn off dependent flags of inst's */ /* waiting for this result. */ for (dwi = 0; dwi < STX->iwin_index2[inum]; dwi++) { inum2 = STX->iwin_dep2 [inum] [dwi]; STX->iwin_flags [inum2] &= ~IWIN_DEP2; CheckInstAvail (STX, inum2); } for (dwi = 0; dwi < STX->iwin_index3[inum]; dwi++) { inum2 = STX->iwin_dep3 [inum] [dwi]; STX->iwin_flags [inum2] &= ~IWIN_DEP3; CheckInstAvail (STX, inum2); } } /* Then release this instruction slot. */ free_inst (STX, inum); } else /* Otherwise, put it back on the queue for next cycle */ { Add_to_worklist (STX, 1, reg_writeback, ix); } }void reg0_writeback (void *st, void *ix) { STX->regs[0] = 0; /* Keep R0 zero */ free_inst (STX, (int) ix); } /* * free_inst - Free up instruction slot in instruction window * * For the precise interrupts model, just set a flag to * indicate that the instruction can be freed. */void free_inst (struct s_cpu_state *st, int inum) { int reg_ix; REGSTAT *rs; INST *ip;#ifdef DEBUG_CHECKS if (!(st->iwin_flags [inum] & IWIN_BUSY)) { fprintf (stderr, "Error: instruction slot already free\r\n"); ms_break (st, NULL, "ERR"); }#ifdef PRECISE if (st->iwin_flags [inum] & IWIN_FREED) { fprintf (stderr, "Error: instruction slot already free\r\n"); ms_break (st, NULL, "ERR"); }#endif /* PRECISE *//* These checks are somewhat expensive. Comment out for now: { int i, pri; for (i=0, pri=st->iwin_head_ldst; (i<10) && (pri >= 0); i++, pri = st->iwin_ldst [pri]) { if (pri == inum) { fprintf (stderr, "Error: freed instruction still in use\r\n"); ms_break (st, NULL, "ERR"); } } for (i=0, pri=st->iwin_headpri; (i<10) && (pri >= 0); i++, pri = st->iwin_pri [pri]) { if (pri == inum) { fprintf (stderr, "Error: freed instruction still in use\r\n"); ms_break (st, NULL, "ERR"); } } for (i=0, pri=st->iwin_next_avail; (i<10) && (pri >= 0); i++, pri = st->iwin_avail_list [pri]) { if (pri == inum) { fprintf (stderr, "Error: freed instruction still in use\r\n"); ms_break (st, NULL, "ERR"); } } for (i=0, pri=st->iwin_nextfree; (i<10) && (pri >= 0); i++, pri = st->iwin_freelist [pri]) { if (pri == inum) { fprintf (stderr, "Error: Error: instruction slot already free\r\n"); ms_break (st, NULL, "ERR"); } } }*/#endif /* DEBUG_CHECKS */#ifdef PRECISE st->iwin_flags [inum] |= IWIN_FREED;#else UnthreadInst (st, inum);#endif /* Decrement reference counts of source */ /* registers for this instruction. */ ip = &st->iwin [inum]; if (ip->r2 > 0) { reg_ix = ip->r2 >> 1; rs = &st->reg_rstat [reg_ix]; rs->reg_ref--; CheckRegFree (st, rs, reg_ix); } if (ip->r3 > 0) { reg_ix = ip->r3 >> 1; rs = &st->reg_rstat [reg_ix]; rs->reg_ref--; CheckRegFree (st, rs, reg_ix); } }#ifndef INLINE /* * UnthreadInst - Remove instruction from its thread and * put it back on the free list. */void UnthreadInst (struct s_cpu_state *st, int inum) { int br_node; /* Remove from the instruction chain of its thread */ br_node = st->iwin_br_node [inum]; if (br_node >= 0) { int tmpi; BrTREE *br; br = &st->branch_tree [br_node]; if ((tmpi = st->iwin_bthread [inum]) >= 0) st->iwin_thread [tmpi] = st->iwin_thread [inum]; else br->iwin_head_th = st->iwin_thread [inum]; if ((tmpi = st->iwin_thread [inum]) >= 0) st->iwin_bthread [tmpi] = st->iwin_bthread [inum]; else br->iwin_tail_th = st->iwin_bthread [inum]; } /* Put instruction back on free list */ st->iwin_freelist [inum] = st->iwin_nextfree; st->iwin_nextfree = inum; st->iwin_flags [inum] = 0; st->iwin_index2 [inum] = 0; st->iwin_index3 [inum] = 0; } /* * AcquireRegMap - Mark physical register mapped, and track * number of times it is mapped. */void AcquireRegMap (REGSTAT *rs, THREAD *th, int lreg) { rs->reg_nmap++; rs->reg_status |= REG_MAPPED; if ((rs->reg_status & REG_CLAIMED) && (th->half_def[lreg >> 1] & REGNAME_CLAIM)) rs->reg_nclaims++; } /* * ReleaseRegMap - Decrement map count for register and mark * it unmapped when the count reaches 0. */void ReleaseRegMap (struct s_cpu_state *st, THREAD *th, int reg_ix, int lreg) { int lreg_ix; REGSTAT *rs; rs = &st->reg_rstat[reg_ix]; rs->reg_nmap--; if (rs->reg_nmap == 0) { rs->reg_status &= ~REG_MAPPED; CheckRegFree (st, rs, reg_ix); } lreg_ix = lreg>>1; if ((rs->reg_status & REG_CLAIMED) && (th->half_def[lreg_ix] & REGNAME_CLAIM)) { rs->reg_nclaims--; CheckRegFree (st, rs, reg_ix); if ((rs->reg_status & REG_CLAIMED) == 0) th->half_def[lreg_ix] &= ~REGNAME_CLAIM; } } /* * CheckRegFree - Update register state * * For normal registers, they become free when the number of * references drops to zero, and there is no other reason to * stay busy (i.e. they aren't still mapped and aren't in the * instruction window). * * In the PRECISE case, when the writer of a register graduates, * the prior name for that register is available. This is * indicated by setting the REG_FREED flag. * * For special registers, they stay mapped all the time, so * just check if they are still in the instruction window. * * For claimed registers (the other half of double precision * registers), unclaim them if writeback has happened, the * number of claims is zero, and the number of references * is zero. This guarantees that a subsequent claimant can * write to the register without interfering with any thread * relying on a prior value in that register. * * The reg number for this routine has already been divided by 2 */void CheckRegFree (struct s_cpu_state *st, REGSTAT *rs, int reg_ix) { if ((rs->reg_status & REG_CLAIMED) && (rs->reg_nclaims <= 0) && (rs->reg_ref <= 0) && ((rs->reg_status & REG_IN_WIN) == 0) ) rs->reg_status &= ~REG_CLAIMED;#ifdef PRECISE if (rs->reg_status & REG_FREED) { if (rs->reg_status & REG_MAPPED) rs->reg_status = REG_MAPPED; else { rs->reg_status = 0; st->reg_freelist [reg_ix] = st->reg_nextfree; st->reg_nextfree = reg_ix; } } if (preg_is_special (reg_ix) && ((rs->reg_status & (REG_BUSY | REG_IN_WIN | REG_MAPPED | REG_DMAP)) == (REG_BUSY + REG_MAPPED)) ) rs->reg_status = REG_MAPPED;#else if ((rs->reg_nclaims <= 0) && (rs->reg_ref <= 0) && ((rs->reg_status & REG_IN_WIN) == 0) ) { if ((rs->reg_status & (REG_BUSY | REG_IN_WIN | REG_MAPPED | REG_DMAP)) == REG_BUSY) { rs->reg_status = 0; st->reg_freelist [reg_ix] = st->reg_nextfree; st->reg_nextfree = reg_ix; } else if (preg_is_special (reg_ix) && ((rs->reg_status & (REG_BUSY | REG_IN_WIN | REG_MAPPED | REG_DMAP)) == (REG_BUSY + REG_MAPPED)) ) rs->reg_status = REG_MAPPED; }#endif /* PRECISE */ } /* * CheckInstAvail - Check if the instruction is now available for * execution * * Inum is the index of the instruction to check */void CheckInstAvail (struct s_cpu_state *st, int inum) {#ifdef DEBUG_CHECKS if (!(st->iwin_flags [inum] & IWIN_BUSY)) { fprintf (stderr, "Instruction slot not in use\r\n"); ms_break (st, NULL, "ERR"); }#endif /* Check if the instruction is unencumbered */ if (st->iwin_flags [inum] &(IWIN_DEP2 | IWIN_DEP3 | IWIN_FLUSH | IWIN_AVAIL | IWIN_LDST_DEP | IWIN_BRDLY)) return; /* Don't allow speculative writes to special registers */ if ((st->iwin_flags [inum] & (IWIN_SPEC | IWIN_CTL)) == (IWIN_SPEC | IWIN_CTL)) return; /* Then mark it available and add it to the available */ /* list. */ st->iwin_flags [inum] |= IWIN_AVAIL;#ifdef PRIORITIZE_AVAIL_LIST /* Insert the instruction into the available list in */ /* priority order. */ pri = st->iwin_headpri; avail = st->iwin_next_avail; last_avail = -1; while (pri != inum) {#ifdef DEBUG_CHECKS if (pri < 0) { fprintf (stderr, "Error - Available instruction not in priority list\r\n"); ms_break (st, NULL, "ERR"); }#endif if (pri == avail) { last_avail = avail; avail = st->iwin_avail_list [avail]; } pri = st->iwin_pri [pri]; } st->iwin_avail_list [inum] = avail; if (last_avail < 0) st->iwin_next_avail = inum; else st->iwin_avail_list [last_avail] = inum;#else /* Otherwise just add newly available instructions */ /* to the tail of the available list. */ if (st->iwin_next_avail >= 0) { st->iwin_avail_list [st->iwin_last_avail] = inum; st->iwin_last_avail = inum; } else { st->iwin_next_avail = inum; st->iwin_last_avail = inum; } st->iwin_avail_list [inum] = -1;#endif }#endif /* !INLINE */ /* * ms_issue - ISSUE instructions that are ready to go. * Chase down the priority chain, issuing the first * available instructions. */void ms_issue (struct s_cpu_state *st) { int pri, prev_pri, reg_ix, ex_count, issues; /* If issue is stalled, skip it and retry execution. */ /* Pending interrupts stall issue. */ if (st->exception_pending) { AddToStat (ST_ISSUE_STALLED, ISSUE_WIDTH); AddToStat (ST_EXCEPT, ISSUE_WIDTH); return; } if (st->stall_issue) { AddToStat (ST_ISSUE_STALLED, ISSUE_WIDTH); AddToStat (st->stall_type, ISSUE_WIDTH);#ifdef DEBUG_CHECKS if (st->stall_type == ST_NO_EXCUSE) { fprintf (stderr, "No excuse stall type\r\n"); ms_break (st, NULL, "ERR"); }#endif return; } AddToStat (ST_ISSUE_TRIED, ISSUE_WIDTH); for (issues=0, ex_count=0; (issues<ISSUE_WIDTH) && (ex_count<(2*ISSUE_WIDTH)); ) { /* Get next available instruction */ pri = st->iwin_next_avail; prev_pri = -1; while (pri >= 0) { if ((st->iwin_flags [pri] & IWIN_LDST) && (!PhaseA (pri))) { /* If it's a memory operation, make */ /* sure that there is room for it. */ if (ldst_buffer_reserve (st) >= 0) break; /* No room, proceed to next instruction */ prev_pri = pri; pri = st->iwin_avail_list [pri]; continue; } break; } if (pri < 0) break; if (pri == st->iwin_next_avail) st->iwin_next_avail = st->iwin_avail_list [pri]; else st->iwin_avail_list [prev_pri] = st->iwin_avail_list [pri]; if (pri == st->iwin_last_avail) st->iwin_last_avail = prev_pri;#ifdef DEBUG_CHECKS if (!(st->iwin_flags [pri] & IWIN_BUSY)) { fprintf (stderr, "Inconsistent instruction window state\r\n"); ms_break (st, NULL, "ERR"); }#endif /* Then issue to execution unit */ st->ex [ex_count++] = pri; st->iwin_flags [pri] |= IWIN_ISSUED; /* and remove from priority chain, */ /* except for Phase A of loads/stores. */ if (st->iwin_flags [pri] & IWIN_LDST) { if (!PhaseA (pri)) {#ifdef PREF_DEBUG { INST *ip = &st->iwin [pri]; if (is_store(ip->op)) CPUPrint("CPU %d ISSUE Store addr = %08x cycle = %d\n", CPUNUM(st), Ireg(ip->r2) + ip->imm, st->work_cycle); else if (is_load(ip->op)) CPUPrint("CPU %d ISSUE Load addr = %08x cycle = %d\n", CPUNUM(st), Ireg(ip->r2) + ip->imm, st->work_cycle); else if (is_prefetch(ip->op)) CPUPrint("CPU %d ISSUE Prefetch addr = %08x cycle = %d\n", CPUNUM(st), Ireg(ip->r2) + ip->imm, st->work_cycle); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -