/** * Flush all frames in the jitter buffer * * @param jb Jitter buffer */ void jbuf_flush(struct jbuf *jb) { struct le *le; if (!jb) return; if (jb->framel.head) { DEBUG_INFO("flush: %u frames\n", jb->n); } /* put all buffered frames back in free list */ for (le = jb->framel.head; le; le = jb->framel.head) { DEBUG_INFO(" flush frame: seq=%u\n", ((struct frame *)(le->data))->hdr.seq); frame_deref(jb, le->data); } jb->n = 0; jb->running = false; STAT_INC(n_flush); }
//************************************************************************** void iwindow_t::squash( pseq_t* the_pseq, int32 last_good, int32 &num_decoded) { #ifdef DEBUG_IWIN DEBUG_OUT("iwindow_t:squash lastgood[%d] num_decoded[%d]\n",last_good,num_decoded); #endif // window index in the m_window uint32 windex; // check that last good is between the last_retired && the last_fetched if ( !rangeOverlap( m_last_retired, m_last_fetched, last_good ) ) { DEBUG_OUT( "squash: warning: last_good = %d. last_fetched = %d. last_retired = %d. [%0llx]\n", last_good, m_last_fetched, m_last_retired, the_pseq->getLocalCycle() ); } #ifdef DEBUG_IWIN DEBUG_OUT("\tafter calling rangeOverlap\n",last_good,num_decoded); #endif if ( ( iwin_increment(last_good) == m_last_retired ) && m_window[last_good] == NULL ) { DEBUG_OUT( "squash: warning: last_good = %d. last_retired = %d. [%0llx]\n", last_good, m_last_retired, the_pseq->getLocalCycle() ); } #ifdef DEBUG_IWIN DEBUG_OUT("\tbegin setting stage_squash \n",last_good,num_decoded); #endif uint32 stage_squash[dynamic_inst_t::MAX_INST_STAGE]; for (uint32 i = 0; i < dynamic_inst_t::MAX_INST_STAGE; i++) { stage_squash[i] = 0; } windex = m_last_fetched; // squash all the fetched instructions (in reverse order) while (windex != m_last_decoded) { if (m_window[windex]) { // FetchSquash double checks this is OK to squash stage_squash[m_window[windex]->getStage()]++; #ifdef DEBUG_IWIN DEBUG_OUT("\tbefore calling FetchSquash\n",last_good,num_decoded); #endif m_window[windex]->FetchSquash(); #ifdef DEBUG_IWIN DEBUG_OUT("\tafter calling FetchSquash\n",last_good,num_decoded); #endif delete m_window[windex]; #ifdef DEBUG_IWIN DEBUG_OUT("\tsetting m_window[windex]=NULL\n",last_good,num_decoded); #endif m_window[windex] = NULL; } else { ERROR_OUT("error: iwindow: fetchsquash(): index %d is NULL\n", windex); SIM_HALT; } windex = iwin_decrement(windex); } // we squash instructions in the opposite order they were fetched, // the process of squashing restores the decode register map. windex = m_last_decoded; // squash all the decoded instructions (in reverse order) while (windex != (uint32) last_good) { // squash modifies the decode map to restore the original mapping if (m_window[windex]) { // if last_good is last_retired, windex may point to NULL entry stage_squash[m_window[windex]->getStage()]++; #ifdef DEBUG_IWIN DEBUG_OUT("\tbefore calling Squash\n",last_good,num_decoded); #endif assert(m_window[windex] != NULL); m_window[windex]->Squash(); #ifdef DEBUG_IWIN DEBUG_OUT("\tafter calling Squash\n",last_good,num_decoded); #endif delete m_window[windex]; #ifdef DEBUG_IWIN DEBUG_OUT("\tsetting m_window[windex]=NULL\n",last_good,num_decoded); #endif m_window[windex] = NULL; } else { ERROR_OUT("error: iwindow: squash(): index %d is NULL\n", windex); SIM_HALT; } windex = iwin_decrement(windex); } // assess stage-based statistics on what was squashed for (uint32 i = 0; i < dynamic_inst_t::MAX_INST_STAGE; i++) { if (stage_squash[i] >= (uint32) IWINDOW_ROB_SIZE) { ERROR_OUT("lots of instructions (%d) squashed from stage: %s\n", stage_squash[i], dynamic_inst_t::printStage( (dynamic_inst_t::stage_t) i )); stage_squash[i] = IWINDOW_ROB_SIZE - 1; } STAT_INC( the_pseq->m_hist_squash_stage[i][stage_squash[i]] ); } // look back through the in-flight instructions, // restoring the most recent "good" branch predictors state windex = last_good; while (windex != m_last_retired) { if (m_window[windex] == NULL) { ERROR_OUT("error: iwindow: inflight: index %d is NULL\n", windex); SIM_HALT; } else { if (m_window[windex]->getStaticInst()->getType() == DYN_CONTROL) { predictor_state_t good_spec_state = (static_cast<control_inst_t*> (m_window[windex]))->getPredictorState(); #ifdef DEBUG_IWIN DEBUG_OUT("\tbefore calling setSpecBPS\n",last_good,num_decoded); #endif the_pseq->setSpecBPS(good_spec_state); #ifdef DEBUG_IWIN DEBUG_OUT("\tafter calling setSpecBPS\n",last_good,num_decoded); #endif break; } } windex = iwin_decrement(windex); } if (windex == m_last_retired) { /* no inflight branch, restore from retired "architectural" state */ #ifdef DEBUG_IWIN DEBUG_OUT("\tbefore calling setSpecBPS (2)\n",last_good,num_decoded); #endif the_pseq->setSpecBPS(*(the_pseq->getArchBPS()) ); #ifdef DEBUG_IWIN DEBUG_OUT("\tafter calling setSpecBPS (2)\n",last_good,num_decoded); #endif } m_last_fetched = last_good; m_last_decoded = last_good; // if we squash in execute, we can flush the decode pipeline, with no trouble // check if logically (m_last_scheduled > last_good) #ifdef DEBUG_IWIN DEBUG_OUT("\tbefore rangeOverlap\n",last_good,num_decoded); #endif if ( rangeOverlap( m_last_retired, m_last_scheduled, last_good ) ) { m_last_scheduled = last_good; num_decoded = 0; ASSERT( rangeSubtract( m_last_decoded, m_last_scheduled ) <= 0 ); } else { #ifdef DEBUG_IWIN DEBUG_OUT("\tbefore calling rangeSubtract\n",last_good,num_decoded); #endif // else, last_good instruction is in decode ... so we need to pass // the number of currently decoded instructions back... num_decoded = (uint32) rangeSubtract( m_last_decoded, m_last_scheduled ); #ifdef DEBUG_IWIN DEBUG_OUT("\tafter calling rangeSubtract\n",last_good,num_decoded); #endif } if (num_decoded > 8) { SIM_HALT; } #ifdef DEBUG_IWIN DEBUG_OUT("iwindow_t::squash END\n",last_good,num_decoded); #endif }
//************************************************************************** void control_inst_t::Retire( abstract_pc_t *a ) { #ifdef DEBUG_DYNAMIC_RET DEBUG_OUT("control_inst_t:Retire BEGIN, proc[%d]\n",m_proc); #endif #ifdef DEBUG_DYNAMIC char buf[128]; s->printDisassemble(buf); DEBUG_OUT("\tcontrol_inst_t::Retire BEGIN %s seq_num[ %lld ] cycle[ %lld ] fetchPC[ 0x%llx ] fetchNPC[ 0x%llx ] PredictedPC[ 0x%llx ] PredictedNPC[ 0x%llx ]\n", buf, seq_num, m_pseq->getLocalCycle(), m_actual.pc, m_actual.npc, m_predicted.pc, m_predicted.npc); for(int i=0; i < SI_MAX_DEST; ++i){ reg_id_t & dest = getDestReg(i); reg_id_t & tofree = getToFreeReg(i); if( !dest.isZero() ){ DEBUG_OUT("\tDest[ %d ] Vanilla[ %d ] Physical[ %d ] Arf[ %s ] ToFree: Vanilla[ %d ] physical[ %d ] Arf[ %s ]\n", i, dest.getVanilla(), dest.getPhysical(), dest.rid_type_menomic( dest.getRtype() ), tofree.getVanilla(), tofree.getPhysical(), tofree.rid_type_menomic( tofree.getRtype() ) ); } } #endif ASSERT( !getEvent( EVENT_FINALIZED ) ); STAT_INC( m_pseq->m_stat_control_retired[m_proc] ); // Need this bc we place fetch barrier on retry instead of stxa: if ( (s->getOpcode() == i_retry) || (s->getFlag( SI_FETCH_BARRIER)) ) { // if we have a branch misprediction, we already unstalled the fetch in partialSquash(): if(getEvent(EVENT_BRANCH_MISPREDICT) == false){ m_pseq->unstallFetch(m_proc); } } STAT_INC( m_pseq->m_branch_seen_stat[s->getBranchType()][2] ); STAT_INC( m_pseq->m_branch_seen_stat[s->getBranchType()][m_priv? 1:0] ); // record when execution takes place m_event_times[EVENT_TIME_RETIRE] = m_pseq->getLocalCycle() - m_fetch_cycle; // update dynamic branch prediction (predicated) instruction statistics static_inst_t *s_instr = getStaticInst(); if (s_instr->getType() == DYN_CONTROL) { uint32 inst; int op2; int pred; switch (s_instr->getBranchType()) { case BRANCH_COND: // conditional branch STAT_INC( m_pseq->m_nonpred_retire_count_stat[m_proc] ); break; case BRANCH_PCOND: // predictated conditional inst = s_instr->getInst(); op2 = maskBits32( inst, 22, 24 ); pred = maskBits32( inst, 19, 19 ); if ( op2 == 3 ) { // integer register w/ predication STAT_INC( m_pseq->m_pred_reg_retire_count_stat[m_proc] ); if (pred) { STAT_INC( m_pseq->m_pred_reg_retire_taken_stat[m_proc] ); } else { STAT_INC( m_pseq->m_pred_reg_retire_nottaken_stat[m_proc] ); } } else { STAT_INC( m_pseq->m_pred_retire_count_stat[m_proc] ); if (pred) { STAT_INC( m_pseq->m_pred_retire_count_taken_stat[m_proc] ); } else { STAT_INC( m_pseq->m_pred_retire_count_nottaken_stat[m_proc] ); } } if (pred == true && m_isTaken == false || pred == false && m_isTaken == true) { STAT_INC( m_pseq->m_branch_wrong_static_stat ); } break; default: ; // ignore non-predictated branches } } #ifdef DEBUG_RETIRE m_pseq->out_info("## Control Retire Stage\n"); printDetail(); m_pseq->printPC( &m_actual ); #endif bool mispredict = (m_events & EVENT_BRANCH_MISPREDICT); if (mispredict) { // incorrect branch prediction STAT_INC( m_pseq->m_branch_wrong_stat[s->getBranchType()][2] ); STAT_INC( m_pseq->m_branch_wrong_stat[s->getBranchType()][m_priv? 1:0] ); //train BRANCH_PRIV predictor if( (s->getBranchType() == BRANCH_PRIV) ){ if (m_predicted.cwp != m_actual.cwp) { m_pseq->getRegstatePred()->update(getVPC(), CONTROL_CWP, m_actual.cwp, m_predicted.cwp); } if (m_predicted.tl != m_actual.tl) { m_pseq->getRegstatePred()->update(getVPC(), CONTROL_TL, m_actual.tl, m_predicted.tl); } if (m_predicted.pstate != m_actual.pstate) { m_pseq->getRegstatePred()->update(getVPC(), CONTROL_PSTATE, m_actual.pstate, m_predicted.pstate); } } //****************************** print out mispredicted inst ***************** if(s->getBranchType() == BRANCH_PRIV){ char buf[128]; s->printDisassemble( buf ); bool imm = s->getFlag(SI_ISIMMEDIATE); #if 0 if(m_predicted.pc != m_actual.pc){ m_pseq->out_info("CONTROLOP: PC mispredict: predicted[ 0x%llx ] actual[ 0x%llx ] type=%s seqnum[ %lld ] VPC[ 0x%llx ] PC[ 0x%llx ] fetched[ %lld ] executed[ %lld ] correctPC[ 0x%llx ] imm[ %d ] %s\n", m_predicted.pc, m_actual.pc, pstate_t::branch_type_menomic[s->getBranchType()], seq_num, getVPC(), getPC(), m_fetch_cycle, m_event_times[EVENT_TIME_EXECUTE] + m_fetch_cycle, m_actual.pc, imm, buf); } #endif #if 0 if(m_predicted.npc != m_actual.npc){ m_pseq->out_info("CONTROLOP: NPC mispredict: predicted[ 0x%llx ] actual[ 0x%llx ] type=%s seqnum[ %lld ] VPC[ 0x%llx ] PC[ 0x%llx ] fetched[ %lld ] executed[ %lld ] correctPC[ 0x%llx ] imm[ %d ] %s\n", m_predicted.npc, m_actual.npc, pstate_t::branch_type_menomic[s->getBranchType()], seq_num, getVPC(), getPC(), m_fetch_cycle, m_event_times[EVENT_TIME_EXECUTE] + m_fetch_cycle, m_actual.pc, imm, buf); } #endif #if 0 if (m_predicted.cwp != m_actual.cwp) { m_pseq->out_info("CONTROLOP: CWP mispredict: predicted[ %d ] actual[ %d ] type=%s seqnum[ %lld ] VPC[ 0x%llx ] PC[ 0x%llx ] fetched[ %lld ] executed[ %lld ] correctPC[ 0x%llx ] imm[ %d ] %s\n", m_predicted.cwp, m_actual.cwp, pstate_t::branch_type_menomic[s->getBranchType()], seq_num, getVPC(), getPC(), m_fetch_cycle, m_event_times[EVENT_TIME_EXECUTE] + m_fetch_cycle, m_actual.pc, imm, buf); } #endif #if 0 if (m_predicted.tl != m_actual.tl) { m_pseq->out_info("CONTROLOP: TL mispredict: predicted[ %d ] actual[ %d ] type=%s seqnum[ %lld ] VPC[ 0x%llx ] PC[ 0x%llx ] fetched[ %lld ] executed[ %lld ] correctPC[ 0x%llx ] imm[ %d ] %s\n", m_predicted.tl, m_actual.tl, pstate_t::branch_type_menomic[s->getBranchType()], seq_num, getVPC(), getPC(), m_fetch_cycle, m_event_times[EVENT_TIME_EXECUTE] + m_fetch_cycle, m_actual.pc, imm, buf); } #endif #if 0 if (m_predicted.pstate != m_actual.pstate) { m_pseq->out_info("CONTROLOP: PSTATE mispredict: predicted[ 0x%0x ] actual[ 0x%0x ] type=%s seqnum[ %lld ] VPC[ 0x%llx ] PC[ 0x%llx ] fetched[ %lld ] executed[ %lld ] correctPC[ 0x%llx ] imm[ %d ] %s\n", m_predicted.pstate, m_actual.pstate, pstate_t::branch_type_menomic[s->getBranchType()], seq_num, getVPC(), getPC(), m_fetch_cycle, m_event_times[EVENT_TIME_EXECUTE] + m_fetch_cycle, m_actual.pc, imm, buf); } #endif } //************************************************************************** // train ras's exception table if (ras_t::EXCEPTION_TABLE && s->getBranchType() == BRANCH_RETURN) { my_addr_t tos; ras_t *ras = m_pseq->getRAS(m_proc); ras->getTop(&(m_pred_state.ras_state), &tos); if(tos == m_actual.npc) { ras->markException(m_predicted.npc); // update RAS state ras->pop(&(m_pred_state.ras_state)); m_pseq->setSpecBPS(m_pred_state); if (ras_t::DEBUG_RAS) m_pseq->out_info("*********** DEBUG_RAS ***********\n"); } else { ras->unmarkException(m_actual.npc); } } // XU DEBUG if (0 && s->getBranchType() == BRANCH_RETURN) { m_pseq->out_info("**** %c:mispred 0x%llx, pred 0x%llx target 0x%llx, " "next %d TOS %d\n", m_priv? 'K':'U', getVPC(), m_predicted.npc, m_actual.npc, m_pred_state.ras_state.next_free, m_pred_state.ras_state.TOS); // print 5 instr after mis-pred generic_address_t addr = m_predicted.npc-8; for(uint32 i = 0; i < 5; i++, addr+=4) { //get the actual seq number for the pointer to m_state: int32 seq_num = m_pseq->getID() / CONFIG_LOGICAL_PER_PHY_PROC; assert(seq_num >= 0 && seq_num < system_t::inst->m_numSMTProcs); tuple_int_string_t *disassemble = SIM_disassemble((processor_t *) system_t::inst->m_state[seq_num]->getSimicsProcessor(m_proc), addr, /* logical */ 1); if (disassemble) m_pseq->out_info(" %s\n", disassemble->string); } } } else { // correct or no prediction STAT_INC( m_pseq->m_branch_right_stat[s->getBranchType()][2] ); STAT_INC( m_pseq->m_branch_right_stat[s->getBranchType()][m_priv? 1:0] ); } /* update branch predictor tables at retirement */ if (s->getBranchType() == BRANCH_COND || s->getBranchType() == BRANCH_PCOND) { m_pseq->getDirectBP()->Update(getVPC(), (m_pseq->getArchBPS()->cond_state), s->getFlag( SI_STATICPRED ), m_isTaken, m_proc); } else if (s->getBranchType() == BRANCH_INDIRECT || (s->getBranchType() == BRANCH_CALL && s->getOpcode() != i_call) ) { // m_actual.npc is the indirect target m_pseq->getIndirectBP()->Update( getVPC(), &(m_pseq->getArchBPS()->indirect_state), m_actual.npc, m_proc ); } m_pseq->setArchBPS(m_pred_state); // no need to update call&return, since we used checkpointed RAS // no update on traps right now SetStage(RETIRE_STAGE); /* retire any register overwritten by link register */ retireRegisters(); #if 0 if(m_actual.pc == (my_addr_t) -1){ char buf[128]; s->printDisassemble(buf); ERROR_OUT("\tcontrol_inst_t::Retire %s seq_num[ %lld ] cycle[ %lld ] fetchPC[ 0x%llx ] fetchNPC[ 0x%llx ] fetched[ %lld ] executed[ %lld ]\n", buf, seq_num, m_pseq->getLocalCycle(), m_actual.pc, m_actual.npc, m_fetch_cycle, m_fetch_cycle+getEventTime(EVENT_TIME_EXECUTE_DONE)); //print out writer cycle for(int i=0; i < SI_MAX_SOURCE; ++i){ reg_id_t & source = getSourceReg(i); if(!source.isZero()){ uint64 written_cycle = source.getARF()->getWrittenCycle( source, m_proc ); uint64 writer_seqnum = source.getARF()->getWriterSeqnum( source, m_proc ); ERROR_OUT("\tSource[ %d ] Vanilla[ %d ] Physical[ %d ] Arf[ %s ] written_cycle[ %lld ] writer_seqnum[ %lld ]\n", i, source.getVanilla(), source.getPhysical(), source.rid_type_menomic( source.getRtype() ), written_cycle, writer_seqnum); } } } #endif ASSERT( m_actual.pc != (my_addr_t) -1 ); /* return pc, npc pair which are the results of execution */ a->pc = m_actual.pc; a->npc = m_actual.npc; markEvent( EVENT_FINALIZED ); #ifdef DEBUG_DYNAMIC_RET DEBUG_OUT("control_inst_t:Retire END, proc[%d]\n",m_proc); #endif }
/** * Put one frame into the jitter buffer * * @param jb Jitter buffer * @param hdr RTP Header * @param mem Memory pointer - will be referenced * * @return 0 if success, otherwise errorcode */ int jbuf_put(struct jbuf *jb, const struct rtp_header *hdr, void *mem) { struct frame *f; struct le *le, *tail; uint16_t seq; int err = 0; if (!jb || !hdr) return EINVAL; seq = hdr->seq; STAT_INC(n_put); if (jb->running) { /* Packet arrived too late to be put into buffer */ if (seq_less((seq + jb->n), jb->seq_put)) { STAT_INC(n_late); DEBUG_INFO("packet too late: seq=%u (seq_put=%u)\n", seq, jb->seq_put); return ETIMEDOUT; } } frame_alloc(jb, &f); tail = jb->framel.tail; /* If buffer is empty -> append to tail Frame is later than tail -> append to tail */ if (!tail || seq_less(((struct frame *)tail->data)->hdr.seq, seq)) { list_append(&jb->framel, &f->le, f); goto out; } /* Out-of-sequence, find right position */ for (le = tail; le; le = le->prev) { const uint16_t seq_le = ((struct frame *)le->data)->hdr.seq; if (seq_less(seq_le, seq)) { /* most likely */ DEBUG_INFO("put: out-of-sequence" " - inserting after seq=%u (seq=%u)\n", seq_le, seq); list_insert_after(&jb->framel, le, &f->le, f); break; } else if (seq == seq_le) { /* less likely */ /* Detect duplicates */ DEBUG_INFO("duplicate: seq=%u\n", seq); STAT_INC(n_dups); list_insert_after(&jb->framel, le, &f->le, f); frame_deref(jb, f); return EALREADY; } /* sequence number less than current seq, continue */ } /* no earlier timestamps found, put in head */ if (!le) { DEBUG_INFO("put: out-of-sequence" " - put in head (seq=%u)\n", seq); list_prepend(&jb->framel, &f->le, f); } STAT_INC(n_oos); out: /* Update last timestamp */ jb->running = true; jb->seq_put = seq; /* Success */ f->hdr = *hdr; f->mem = mem_ref(mem); return err; }
//************************************************************************** void control_inst_t::Execute() { STAT_INC( m_pseq->m_stat_control_exec[m_proc] ); m_event_times[EVENT_TIME_EXECUTE_DONE] = m_pseq->getLocalCycle() - m_fetch_cycle; // call the appropriate function static_inst_t *si = getStaticInst(); char buf[128]; s->printDisassemble(buf); if (true) { #ifdef DEBUG_DYNAMIC char buf[128]; s->printDisassemble(buf); DEBUG_OUT("[ %d ] control_inst_t: EXECUTE %s NAV[ %d ] seqnum[ %lld ] fetched[ %lld ] cycle[ %lld ]", m_pseq->getID(), buf, getInstrNAV(), seq_num, m_fetch_cycle, m_pseq->getLocalCycle()); //print source and dest regs DEBUG_OUT(" SOURCES: "); for(int i=0; i < SI_MAX_SOURCE; ++i){ reg_id_t & source = getSourceReg(i); if(!source.isZero()){ DEBUG_OUT("( [%d] V: %d P: %d Arf: %s WriterSN: %lld WrittenCycle: %lld State: 0x%x)", i,source.getVanilla(), source.getPhysical(), source.rid_type_menomic( source.getRtype() ), source.getARF()->getWriterSeqnum( source, m_proc ), source.getARF()->getWrittenCycle( source, m_proc ), source.getVanillaState() ); } } DEBUG_OUT(" DESTS: "); for(int i=0; i < SI_MAX_DEST; ++i){ reg_id_t & dest = getDestReg(i); if(!dest.isZero()){ DEBUG_OUT("( [%d] V: %d P: %d Arf: %s )", i,dest.getVanilla(), dest.getPhysical(), dest.rid_type_menomic( dest.getRtype() )); } } DEBUG_OUT("\n"); #endif // execute the instruction using the jump table pmf_dynamicExecute pmf = m_jump_table[si->getOpcode()]; (this->*pmf)(); // Due to functional bugs sometimes m_actual.pc will be -1 //ASSERT( m_actual.pc != (my_addr_t) -1 ); } else { // NOT executed! dp_control_t dp_value; dp_value.m_at = &m_actual; dp_value.m_taken = false; dp_value.m_annul = si->getAnnul(); dp_value.m_offset = si->getOffset(); // do the operation exec_fn_execute( (i_opcode) si->getOpcode(), (dp_int_t *) &dp_value ); // write result back to this dynamic instruction m_isTaken = dp_value.m_taken; } SetStage(COMPLETE_STAGE); #ifdef DEBUG_DYNAMIC char buf[128]; s->printDisassemble(buf); DEBUG_OUT("control_inst_t: AFTER Execute %s NAV[ %d ] seqnum[ %lld ] fetched[ %lld ] cycle[ %lld ] PredPC[ 0x%llx ] ActualPC[ 0x%llx ] PredNPC[ 0x%llx ] ActualNPC[ 0x%llx ] PredCWP[ 0x%x ] ActualCWP[ 0x%x ] PredTL[ 0x%x ] ActualTL[ 0x%x ] PredPstate[ 0x%x ] ActualPstate[ 0x%x ]\n", buf, getInstrNAV(), seq_num, m_fetch_cycle, m_pseq->getLocalCycle(), m_predicted.pc, m_actual.pc, m_predicted.npc, m_actual.npc, m_predicted.cwp, m_actual.cwp, m_predicted.tl, m_actual.tl, m_predicted.pstate, m_actual.pstate); #endif // All control op should be checked, all of them can mis-predict // if the predicted PC, nPC pairs don't match with actual, cause exeception if ( (m_predicted.pc != m_actual.pc || m_predicted.npc != m_actual.npc || m_predicted.cwp != m_actual.cwp || m_predicted.tl != m_actual.tl || m_predicted.pstate != m_actual.pstate) ) { /* There was a branch mis-prediction -- * patch up branch predictor state */ #ifdef DEBUG_DYNAMIC char buf[128]; s->printDisassemble(buf); DEBUG_OUT("[ %d ] control_inst_t: MISPREDICT %s NAV[ %d ] seqnum[ %lld ] fetched[ %lld ] cycle[ %lld ] PredPC[ 0x%llx ] ActualPC[ 0x%llx ] PredNPC[ 0x%llx ] ActualNPC[ 0x%llx ] PredCWP[ 0x%x ] ActualCWP[ 0x%x ] PredTL[ 0x%x ] ActualTL[ 0x%x ] PredPstate[ 0x%x ] ActualPstate[ 0x%x ]\n", m_pseq->getID(), buf, getInstrNAV(), seq_num, m_fetch_cycle, m_pseq->getLocalCycle(), m_predicted.pc, m_actual.pc, m_predicted.npc, m_actual.npc, m_predicted.cwp, m_actual.cwp, m_predicted.tl, m_actual.tl, m_predicted.pstate, m_actual.pstate); #endif // This preformatted debugging information is left for your convenience // NOT very useful here, bc this might indicate a misprediction AFTER another misprediction // print this out inside Retire()! /* char buf[128]; s->printDisassemble( buf ); if (m_predicted.cwp != m_actual.cwp) { m_pseq->out_info("CONTROLOP: CWP mispredict: predicted[ %d ] actual[ %d ] type=%s seqnum[ %lld ] VPC[ 0x%llx ] PC[ 0x%llx ] fetched[ %lld ] executed[ %lld ] correctPC[ 0x%llx ] %s\n", m_predicted.cwp, m_actual.cwp, pstate_t::branch_type_menomic[s->getBranchType()], seq_num, getVPC(), getPC(), m_fetch_cycle, m_event_times[EVENT_TIME_EXECUTE] + m_fetch_cycle, m_actual.pc, buf); } if (m_predicted.tl != m_actual.tl) { m_pseq->out_info("CONTROLOP: TL mispredict: predicted[ %d ] actual[ %d ] type=%s seqnum[ %lld ] VPC[ 0x%llx ] PC[ 0x%llx ] fetched[ %lld ] executed[ %lld ] correctPC[ 0x%llx ] %s\n", m_predicted.tl, m_actual.tl, pstate_t::branch_type_menomic[s->getBranchType()], seq_num, getVPC(), getPC(), m_fetch_cycle, m_event_times[EVENT_TIME_EXECUTE] + m_fetch_cycle, m_actual.pc, buf); } if (m_predicted.pstate != m_actual.pstate) { m_pseq->out_info("CONTROLOP: PSTATE mispredict: predicted[ 0x%0x ] actual[ 0x%0x ] type=%s seqnum[ %lld ] VPC[ 0x%llx ] PC[ 0x%llx ] fetched[ %lld ] executed[ %lld ] correctPC[ 0x%llx ] %s\n", m_predicted.pstate, m_actual.pstate, pstate_t::branch_type_menomic[s->getBranchType()], seq_num, getVPC(), getPC(), m_fetch_cycle, m_event_times[EVENT_TIME_EXECUTE] + m_fetch_cycle, m_actual.pc, buf); } */ markEvent(EVENT_BRANCH_MISPREDICT); if (s->getBranchType() == BRANCH_COND || s->getBranchType() == BRANCH_PCOND ) { // flip the last bit of the history to correct the misprediction m_pred_state.cond_state = m_pred_state.cond_state ^ 1; } else if (s->getBranchType() == BRANCH_INDIRECT || (s->getBranchType() == BRANCH_CALL && s->getOpcode() != i_call) ) { /* m_pseq->out_info(" INDIRECT: predicted 0x%0llx, 0x%0llx\n", m_predicted.pc, m_predicted.npc); m_pseq->out_info(" INDIRECT: actual 0x%0llx, 0x%0llx\n", m_actual.pc, m_actual.npc); */ m_pseq->getIndirectBP()->FixupState(&(m_pred_state.indirect_state), getVPC()); } // no predictor fixup on PRIV, TRAP or TRAP_RETURN right now // TASK: should update the BTB here // TASK: determine the fetch location (and state) m_actual.gset = pstate_t::getGlobalSet( m_actual.pstate ); /* cause a branch misprediction exception */ m_pseq->raiseException(EXCEPT_MISPREDICT, getWindowIndex(), (enum i_opcode) s->getOpcode(), &m_actual, 0, BRANCHPRED_MISPRED_PENALTY, m_proc ); } }