void FE_stage()
{
  /* only part of FE_stage function is implemented */ 
  /* please complete the rest of FE_stage function */ 
	
	
	if(FE_latch->stage_stall==false)	//check if no pipeline stalled
	{
		Op* new_op = get_free_op();	//get a placeholder op out of the pool
		if(get_op(new_op))		//copy op from trace into the placeholder op
		{
			if((new_op->opcode>=OP_FMEM)&&(new_op->opcode<=OP_FCMO)){
				float_count++;
			}
			if((new_op->opcode>=OP_IADD)&&(new_op->opcode<=OP_MM)){
				integer_count++;
			}
			if((new_op->opcode>=OP_CF)&&(new_op->opcode<=OP_LDA)){
				if(new_op->opcode==OP_CF) branch_count++;				
				integer_count++;
			}
			if((new_op->opcode>=OP_LDA)&&(new_op->opcode<=OP_LD)){
				load_count++;
			}
			if((new_op->opcode==OP_MM)||(new_op->opcode==OP_IMUL)){
				multiple_count++;
			}

			if(new_op->opcode==OP_ST){
				store_count++;
			}			
			if((new_op->opcode == OP_CF) && new_op->cf_type==CF_CBR && use_bpred==true)
			{
				uint64_t pc = new_op->instruction_addr;
				bool predicted_dir=0;		
				predicted_dir=bpred_access(branchpred,pc);
				bpred_update(branchpred,pc,predicted_dir,new_op->actually_taken);
				if(new_op->actually_taken != predicted_dir)
				{
					new_op->mispredicted_branch=true;
				}
				bpred_mispred_count=branchpred->mispred;
				bpred_okpred_count=branchpred->okpred;
			}

			FE_latch->op=new_op;
			FE_latch->op_valid=true;
		}
		else
			free_op(new_op);
	}
	
  //   next_pc = pc + op->inst_size;  // you need this code for building a branch predictor 

}
/* start simulation, program loaded, processor precise state initialized */
void
sim_main(void)
{
  md_inst_t inst;
  register md_addr_t addr, target_PC = 0;
  enum md_opcode op;
  register int is_write;
  int stack_idx;
  enum md_fault_type fault;

  fprintf(stderr, "sim: ** starting functional simulation w/ predictors **\n");

  /* set up initial default next PC */
  SET_NPC(CPC + sizeof(md_inst_t));

  /* check for DLite debugger entry condition */
  if (dlite_check_break(regs.regs_PC, /* no access */0, /* addr */0, 0, 0))
    dlite_main(regs.regs_PC - sizeof(md_inst_t), regs.regs_PC,
         sim_num_insn, &regs, mem);

  while (TRUE) {
    /* maintain $r0 semantics */
    regs.regs_R[MD_REG_ZERO] = 0;

#ifdef TARGET_ALPHA
    regs.regs_F.d[MD_REG_ZERO] = 0.0;
#endif

    /* get the next instruction to execute */
    MD_FETCH_INST(inst, mem, regs.regs_PC);

    /* keep an instruction count */
    sim_num_insn++;

    /* set default reference address and access mode */
    addr = 0;
    is_write = FALSE;

    /* set default fault - none */
    fault = md_fault_none;

    /* decode the instruction */
    MD_SET_OPCODE(op, inst);

    /* execute the instruction */
    switch (op) {
#define DEFINST(OP,MSK,NAME,OPFORM,RES,FLAGS,O1,O2,I1,I2,I3) \
case OP:                                                     \
        SYMCAT(OP,_IMPL);                                    \
        break;

#define DEFLINK(OP,MSK,NAME,MASK,SHIFT)                      \
      case OP:                                               \
        panic("attempted to execute a linking opcode");

#define CONNECT(OP)

#define DECLARE_FAULT(FAULT)            \
  { fault = (FAULT); break; }
#include "machine.def"
default:
  panic("attempted to execute a bogus opcode");
    }

    if (fault != md_fault_none)
      fatal("fault (%d) detected @ 0x%08p", fault, regs.regs_PC);

    if (MD_OP_FLAGS(op) & F_MEM) {
      sim_num_refs++;
      if (MD_OP_FLAGS(op) & F_STORE)
        is_write = TRUE;
    }

    if (MD_OP_FLAGS(op) & F_CTRL) {
      md_addr_t pred_PC;
      struct bpred_update_t update_rec;

      sim_num_branches++;

      if (pred) {
        /* get the next predicted fetch address */
        pred_PC = bpred_lookup(
            pred,
            regs.regs_PC,      // branch addr
            target_PC,         // target addr
            op,                // instruction opcode
            MD_IS_CALL(op),    // call?
            MD_IS_RETURN(op),  // return?
            &update_rec,       // stack an update ptr
            &stack_idx);       // stash return stack ptr

        /* valid address returned from branch predictor? */
        if (!pred_PC) {
          /* no predicted taken target, attempt not taken target */
          pred_PC = regs.regs_PC + sizeof(md_inst_t);
        }

        bpred_update(
            pred,
            CPC,                                 // branch addr
            NPC,                                 // resolved branch target
            NPC != CPC + sizeof(md_inst_t),      // taken?
            pred_PC != CPC + sizeof(md_inst_t),  // pred taken?
            pred_PC == NPC,                      // correct pred?
            op,                                  // opcode
            &update_rec);                        // predictor update pointer
      }
    }

    /* check for DLite debugger entry condition */
    if (dlite_check_break(NPC,
                          is_write ? ACCESS_WRITE : ACCESS_READ,
                          addr,
                          sim_num_insn,
                          sim_num_insn)) {
      dlite_main(regs.regs_PC, NPC, sim_num_insn, &regs, mem);
    }

    /* go to the next instruction */
    UPDATE_PC

    /* finish early? */
    if (max_insts && sim_num_insn >= max_insts)
      return;
  }
}
Example #3
0
void FE_stage()
{

	if(stop_fetching)
		return;

	if(have_to_send_EOS)
	{
		if(sendEOS())
		{
			stop_fetching = true;
			have_to_send_EOS = false;
		}
		return;
	}

	#if 0
	if(FE_latch->op_valid || FE_latch->pipeline_stall_enabled)
	{
		/* Data inside the latch is valid and next stage is still using it.
		Or ID stage has enabled pipeline stalling because of a branch instruction.
		Do not fetch */
		return;
	}
	/* This condition is rewritten for multithreading. See following statements.
	~(a OR b) ===>  ~a AND ~b */
	#endif

	static UINT64 fetch_arbiter = 0;
	int stream_id = -1;
	Op *op;
	bool op_exists = false, stalled[HW_MAX_THREAD];

	for(int i = 0 ; i < HW_MAX_THREAD ; i++)
		stalled[i] = true;

	/* Find next available empty queue slot to fill */
	for(int i = 0 ; i < thread_count ; i++)
	{
		stream_id = fetch_arbiter++ % thread_count;
		if(!FE_latch->op_valid_thread[stream_id] && !FE_latch->pipeline_stall_enabled_thread[stream_id])
		{
			stalled[stream_id] = false;
			op = get_free_op();
			op_exists = get_op(op, stream_id);
			if(op_exists)
				break;
			else
				free_op(op);
		}
	}
	
	if(!op_exists)
	{
		/* No op fetched - this could be due to following : 
		   1. all threads were stalled
		   2. some threads were stalled and others have run out of instructions
		   3. no instructions available to fetch
		*/

		// checking case 1
		bool all_stalled = true;
		for(int i = 0 ; i < thread_count ; i++)
		{
			if(!stalled[i])
				all_stalled = false;
		}
		if(all_stalled)
			return;

		// checking case 2 & 3
		bool eois = true;	// end of instruction streams
		for(int i = 0 ; i < thread_count ; i++)
		{
			if(!end_of_stream[i])
				eois = false;
		}
		if(!eois)
			return;
		else
		{
			/* Must take actions for initiating simulator shut down */
			// first it should be seen if there is some space in queue.
			// if no, then try to send in next cycle
			if(sendEOS())
				stop_fetching = true;
			else
				have_to_send_EOS = true;
			return;
		}
	}

	/* If the op is an branch other than conditional branch, assume that it is predicted correctly,
	if the branch predictor is used */
	//  if(use_bpred && (op->cf_type >= CF_BR) && (op->cf_type < NUM_CF_TYPES) && (op->cf_type != CF_CBR))
	//	  bpred_okpred_count++;
	/* Above 2 lines commented because its not the way solution is implemented */

	/* If we are using branch predictor and type of opcode is conditional branch,
	get a prediction and update GHR and PHT */
	if(use_bpred && (op->cf_type == CF_CBR))
	{
		int prediction = bpred_access(branchpred, op->instruction_addr, op->thread_id);
		if(prediction == op->actually_taken)
		{
			bpred_okpred_count++;
			bpred_okpred_count_thread[op->thread_id]++;
		}
		else
		{
			bpred_mispred_count++;
			bpred_mispred_count_thread[op->thread_id]++;
			/* stall the pipeline if we mispredict */
			FE_latch->pipeline_stall_enabled_thread[op->thread_id] = true;;
			FE_latch->stall_enforcer_thread[op->thread_id] = op->inst_id;
		}
		bpred_update(branchpred,op->instruction_addr,prediction,op->actually_taken, op->thread_id);
	}

	/* hwsim : get the instruction and pass to ID phase */
	# if 0
	/* Deprecated  after adding MT support */
	FE_latch->op = op;				/* pass the op to ID stage */
	FE_latch->op_valid = true;			/* Mark it as valid */
	#endif

	FE_latch->op_queue[op->thread_id] = op;
	FE_latch->op_valid_thread[op->thread_id] = true;

}
Example #4
0
/* start simulation, program loaded, processor precise state initialized */
void
sim_main(void)
{
  md_inst_t inst;
  register md_addr_t addr, target_PC;
  enum md_opcode op;
  register int is_write;
  int stack_idx;
  enum md_fault_type fault;
  int setPC, in_flow = FALSE, flow_index, nflow;
  struct md_uop_t flowtab[MD_MAX_FLOWLEN];

  fprintf(stderr, "sim: ** starting functional simulation w/ predictors **\n");

  /* set up initial default next PC */
  regs.regs_NPC = regs.regs_PC + sizeof(md_inst_t);

  /* synchronize register files... */
  regs.regs_R[MD_REG_PC] = regs.regs_PC;

  /* check for DLite debugger entry condition */
  if (dlite_check_break(regs.regs_PC, /* no access */0, /* addr */0, 0, 0))
    dlite_main(regs.regs_PC - sizeof(md_inst_t), regs.regs_PC,
	       sim_num_insn, &regs, mem);

  while (TRUE)
    {
      /* maintain $r0 semantics */
#ifndef TARGET_ARM
      regs.regs_R[MD_REG_ZERO] = 0;
#endif
#ifdef TARGET_ALPHA
      regs.regs_F.d[MD_REG_ZERO] = 0.0;
#endif /* TARGET_ALPHA */

      /* set default reference address and access mode */
      addr = 0; is_write = FALSE;

      /* set default fault - none */
      fault = md_fault_none;

      if (!in_flow)
	{
	  /* keep an instruction count */
	  sim_num_insn++;

	  /* get the next instruction to execute */
	  MD_FETCH_INST(inst, mem, regs.regs_PC);

	  /* decode the instruction */
	  MD_SET_OPCODE(op, inst);

	  if (MD_OP_FLAGS(op) & F_CISC)
	    {
	      /* get instruction flow */
	      nflow = md_get_flow(op, inst, flowtab);
	      if (nflow > 0)
		{
		  in_flow = TRUE;
		  flow_index = 0;
		}
	      else
		fatal("could not locate CISC flow");
	      sim_num_uops += nflow;
	    }
	  else
	    sim_num_uops++;
	}
      if (in_flow)
	{
	  op = flowtab[flow_index].op;
	  inst = flowtab[flow_index++].inst;
	  if (flow_index == nflow)
	    in_flow = FALSE;
	}

      if (op == NA)
	panic("bogus opcode detected @ 0x%08p", regs.regs_PC);
      if (MD_OP_FLAGS(op) & F_CISC)
	panic("CISC opcode decoded");

      setPC = 0;
      regs.regs_R[MD_REG_PC] = regs.regs_PC;

      /* execute the instruction */
      switch (op)
	{
#define DEFINST(OP,MSK,NAME,OPFORM,RES,FLAGS,O1,O2,O3,I1,I2,I3,I4)	\
	case OP:							\
          SYMCAT(OP,_IMPL);						\
          break;
#define DEFUOP(OP,NAME,OPFORM,RES,FLAGS,O1,O2,O3,I1,I2,I3,I4)		\
	case OP:							\
          SYMCAT(OP,_IMPL);						\
          break;
#define DEFLINK(OP,MSK,NAME,MASK,SHIFT)					\
        case OP:							\
          panic("attempted to execute a linking opcode");
#define CONNECT(OP)
#define DECLARE_FAULT(FAULT)						\
	  { fault = (FAULT); break; }
#include "machine.def"
	default:
	  panic("attempted to execute a bogus opcode");
      }

      if (fault != md_fault_none)
	fatal("fault (%d) detected @ 0x%08p", fault, regs.regs_PC);

      if (setPC != 0/* regs.regs_R[MD_REG_PC] != regs.regs_PC */)
	regs.regs_NPC = regs.regs_R[MD_REG_PC];

      if (MD_OP_FLAGS(op) & F_MEM)
	{
	  sim_num_refs++;
	  if (MD_OP_FLAGS(op) & F_STORE)
	    is_write = TRUE;
	}

      if (MD_OP_FLAGS(op) & F_CTRL)
	{
	  md_addr_t pred_PC;
	  struct bpred_update_t update_rec;

	  sim_num_branches++;

	  if (pred)
	    {
	      /* get the next predicted fetch address */
	      pred_PC = bpred_lookup(pred,
				     /* branch addr */regs.regs_PC,
				     /* target */target_PC,
				     /* inst opcode */op,
				     /* call? */MD_IS_CALL(op),
				     /* return? */MD_IS_RETURN(op),
				     /* stash an update ptr */&update_rec,
				     /* stash return stack ptr */&stack_idx);

	      /* valid address returned from branch predictor? */
	      if (!pred_PC)
		{
		  /* no predicted taken target, attempt not taken target */
		  pred_PC = regs.regs_PC + sizeof(md_inst_t);
		}

	      bpred_update(pred,
			   /* branch addr */regs.regs_PC,
			   /* resolved branch target */regs.regs_NPC,
			   /* taken? */regs.regs_NPC != (regs.regs_PC +
							 sizeof(md_inst_t)),
			   /* pred taken? */pred_PC != (regs.regs_PC +
							sizeof(md_inst_t)),
			   /* correct pred? */pred_PC == regs.regs_NPC,
			   /* opcode */op,
			   /* predictor update pointer */&update_rec);
	    }
	}

      /* check for DLite debugger entry condition */
      if (dlite_check_break(regs.regs_NPC,
			    is_write ? ACCESS_WRITE : ACCESS_READ,
			    addr, sim_num_insn, sim_num_insn))
	dlite_main(regs.regs_PC, regs.regs_NPC, sim_num_insn, &regs, mem);

      /* go to the next instruction */
      if (!in_flow)
	{
	  regs.regs_PC = regs.regs_NPC;
	  regs.regs_NPC += sizeof(md_inst_t);
	}

      /* finish early? */
      if (max_insts && sim_num_insn >= max_insts)
	return;
    }
}
Example #5
0
/* start simulation, program loaded, processor precise state initialized */
void
sim_main(void)
{
  md_inst_t inst;
  register md_addr_t addr, target_PC;
  enum md_opcode op;
  register int is_write;
  int stack_idx;
  enum md_fault_type fault;

  int out1, out2, in1, in2, in3;	  /* register names */
  int v_out1, v_out2, v_in1, v_in2, v_in3;/* register values */
  int vl_out1, vl_out2, vl_in1, vl_in2, vl_in3;
  md_addr_t addr_dispatch;              /* access_address */
  int m_size;                           /* access_size */
  FILE *stream;
  md_addr_t predicted_PC;

  fprintf(stderr, "sim: ** starting functional simulation w/ predictors **\n");

  /* set up initial default next PC */
  regs.regs_NPC = regs.regs_PC + sizeof(md_inst_t);

  /* check for DLite debugger entry condition */
  if (dlite_check_break(regs.regs_PC, /* no access */0, /* addr */0, 0, 0))
    dlite_main(regs.regs_PC - sizeof(md_inst_t), regs.regs_PC,
	       sim_num_insn, &regs, mem);

  while (TRUE)
    {
      /* maintain $r0 semantics */
      regs.regs_R[MD_REG_ZERO] = 0;
#ifdef TARGET_ALPHA
      regs.regs_F.d[MD_REG_ZERO] = 0.0;
#endif /* TARGET_ALPHA */

      /* get the next instruction to execute */
      mem_access(mem, Read, regs.regs_PC, &inst, sizeof(md_inst_t));

      /* keep an instruction count */
      sim_num_insn++;

      /* set default reference address and access mode */
      addr = 0; is_write = FALSE;

      /* set default fault - none */
      fault = md_fault_none;

      /* decode the instruction */
      MD_SET_OPCODE(op, inst);

      /* execute the instruction */
      switch (op)
	{
#define DEFINST(OP,MSK,NAME,OPFORM,RES,CLASS,O1,O2,I1,I2,I3,            \
                VO1,LO1,VO2,LO2,ADDR,VI1,LI1,VI2,LI2,VI3,LI3,M_Size)    \
	case OP:							\
	  in1 = I1; in2 = I2; in3 = I3;					\
	  v_in1 = VI1; v_in2 = VI2; v_in3 = VI3;			\
	  vl_in1 = LI1; vl_in2 = LI2; vl_in3 = LI3;			\
          SYMCAT(OP,_IMPL);						\
	  out1 = O1; out2 = O2;						\
	  v_out1 = VO1; v_out2 = VO2;					\
	  vl_out1 = LO1; vl_out2 = LO2;					\
	  addr_dispatch = ADDR;						\
	  m_size = M_Size;						\
          break;
#define DEFLINK(OP,MSK,NAME,MASK,SHIFT)					\
        case OP:							\
          panic("attempted to execute a linking opcode");
#define CONNECT(OP)
#define DECLARE_FAULT(FAULT)						\
	  { fault = (FAULT); break; }
#include "operand.def"
	default:
	  panic("attempted to execute a bogus opcode");
      }

      if (fault != md_fault_none)
	fatal("fault (%d) detected @ 0x%08p", fault, regs.regs_PC);

      if (MD_OP_FLAGS(op) & F_MEM)
	{
	  sim_num_refs++;
	  if (MD_OP_FLAGS(op) & F_STORE)
	    is_write = TRUE;
	}

      if (MD_OP_FLAGS(op) & F_CTRL)
	{
	  md_addr_t pred_PC;
	  struct bpred_update_t update_rec;

	  sim_num_branches++;

	  if (pred)
	    {
	      /* get the next predicted fetch address */
	      pred_PC = bpred_lookup(pred,
				     /* branch addr */regs.regs_PC,
				     /* target */target_PC,
				     /* inst opcode */op,
				     /* call? */MD_IS_CALL(op),
				     /* return? */MD_IS_RETURN(op),
				     /* stash an update ptr */&update_rec,
				     /* stash return stack ptr */&stack_idx);

	      /* valid address returned from branch predictor? */
	      if (!pred_PC)
		{
		  /* no predicted taken target, attempt not taken target */
		  pred_PC = regs.regs_PC + sizeof(md_inst_t);
		}

	      bpred_update(pred,
			   /* branch addr */regs.regs_PC,
			   /* resolved branch target */regs.regs_NPC,
			   /* taken? */regs.regs_NPC != (regs.regs_PC +
							 sizeof(md_inst_t)),
			   /* pred taken? */pred_PC != (regs.regs_PC +
							sizeof(md_inst_t)),
			   /* correct pred? */pred_PC == regs.regs_NPC,
			   /* opcode */op,
			   /* predictor update pointer */&update_rec);
	    }
	  predicted_PC = pred_PC;
	}

      /*   ここから下を見ればどの変数に何が入っているか分かるはず。 */
      stream = stdout;
      fprintf(stream, "############################################################ \n");
      fprintf(stream, " --- trace count(%d) \n", (int)sim_num_insn);
      fprintf(sim_fd, "%s, inst: `",
      fprintf(stream, "       opcode: %s, inst: `",
	      MD_OP_NAME(op));
      md_print_insn(inst, regs.regs_PC, stream);
      fprintf(stream, "'\n");
      myfprintf(stream, "         PC: 0x%08p, NPC: 0x%08p",
		regs.regs_PC, regs.regs_NPC);
      if(pred)
	myfprintf(stream, " (pred_PC: 0x%08p)\n",
		  regs.regs_PC, regs.regs_NPC, predicted_PC);
      else
	myfprintf(stream, "\n");
      fprintf(stream," |  in(r%02d,r%02d,r%02d),out(r%02d,r%02d),\n",
	      in1, in2, in3, out1, out2);
      fprintf(stream," |  IN(%8x,%8x,%8x),OUT(%8x,%8x)addr(%8x)|\n",
	      v_in1, v_in2, v_in3, v_out1, v_out2, addr_dispatch);
      /* ダブルワードだった場合,この変数がセットされる */
      fprintf(stream," |  in(%8x,%8x,%8x),out(%8x,%8x)         |\n",
	      vl_in1, vl_in2, vl_in3, vl_out1, vl_out2);

      /* machine.h をみるとopから命令の種類を判別する方法が分かる。以下は例 */
      if (op == MD_NOP_OP)
	{
	  fprintf(stream, "   NOP instruction \n");
	}
      else if (MD_OP_FLAGS(op) & F_MEM)
	{
	  fprintf(stream, "   MEMORY instruction \n");
	  if (MD_OP_FLAGS(op) & F_STORE)
	    fprintf(stream, "        store instruction \n");
	  else if (MD_OP_FLAGS(op) & F_LOAD)
	    fprintf(stream, "        load instruction \n");
	  fprintf(stream, "          ld/st address is %010x\n",
		  addr_dispatch);
	  fprintf(stream, "          ld/st size is %2d\n",
		  m_size);
	  /* ロードストアがバイト単位なのか,ワード単位なのか,
	     ハーフワード単位なのかは,opを見て判断できる。
	     例えば, md_op2name[op] が "sh"ならハーフワードである。
	     しかし、これだと面倒なのでoperand.defを改良した方が良い
	     かも知れない。これはおまかせ。
	     */
	  
	  /* ロードストアの詳細に関しては,machine.def を参照。
	     例えば,store halfの場合,(machine.def をエディタで開いて
	     "sh"と言う文字列をサーチすれば該当箇所が見つかる)
	     以下のようにかかれている。*/
	  /*
                #define SH_IMPL                                     
                  {                                                 
                    half_t _src;                                    
                    enum md_fault_type _fault;                      
                    _src = (half_t)(word_t)GPR(RT);                 
                    WRITE_HALF(_src, GPR(BS) + OFS, _fault);        
                    if (_fault != md_fault_none)                    
                      DECLARE_FAULT(_fault);                        
                   }
		   */
	  /*ここで、GPR(BS)はBS番レジスタの値 OFS はオフセットを示す。
	    そして,GPR(RT)はRT番レジスタの値を示す。
	    そしてWRITE_HALF(_src, GPR(BS) + OFS, _fault);は
	    値 _src をアドレス GPR(BS) + OFS に書き込む事を意味する。
	    書き込みのサイズは,halfワードである。*/
	}
      else if (MD_OP_FLAGS(op) & F_CTRL)
	{
	  fprintf(stream, "   BRANCH instruction \n");
	  if (MD_IS_CALL(op))
	    fprintf(stream, "        function call \n");
	  else if (MD_IS_RETURN(op))
	    fprintf(stream, "        function return \n");
	  else if (MD_IS_INDIR(op))
	    fprintf(stream, "        indirect jump \n");
	  else if ((MD_OP_FLAGS(op) & (F_CTRL|F_DIRJMP)) == (F_CTRL|F_DIRJMP))
	    fprintf(stream, "        direct jump \n");
	}
      else
	{
	  fprintf(stream, "   other instruction \n");
	}
      /* この応用として,いきなりopからstoreを判別するには,以下のようにすれば良い*/
      if ((MD_OP_FLAGS(op) & (F_MEM|F_STORE)) == (F_MEM|F_STORE))
	{
	  /*fprintf(stream, "   store instruction \n");*/
	}
      else if ((MD_OP_FLAGS(op) & (F_MEM|F_LOAD)) == (F_MEM|F_LOAD))
	{
	  /*fprintf(stream, "   load instruction \n");*/
	}

      /* ここまで */


      /* check for DLite debugger entry condition */
      if (dlite_check_break(regs.regs_NPC,
			    is_write ? ACCESS_WRITE : ACCESS_READ,
			    addr, sim_num_insn, sim_num_insn))
	dlite_main(regs.regs_PC, regs.regs_NPC, sim_num_insn, &regs, mem);

      /* go to the next instruction */
      regs.regs_PC = regs.regs_NPC;
      regs.regs_NPC += sizeof(md_inst_t);

      /* finish early? */
      if (max_insts && sim_num_insn >= max_insts)
	return;
    }
}