const char *asm_s(instruction_id_t ii) { tuple_int_string_t *tuple; attr_value_t pc; pc = SIM_instruction_read_input_reg(ii, V9_Reg_Id_PC); if (pc.kind != Sim_Val_Integer) { SIM_clear_exception(); return "<unknown pc>"; } SIM_clear_exception(); tuple = SIM_disassemble(SIM_instruction_cpu(ii), (logical_address_t)pc.u.integer, 1); if (SIM_get_pending_exception()) { SIM_clear_exception(); return "<disass error>"; } vtsprintf(tmp_buf, "<0x%016llx> %s", (logical_address_t)pc.u.integer, tuple->string); return (const char *)tmp_buf; }
//************************************************************************** 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 }