Example #1
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;
    }
}
/* 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
/* 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;
    }
}