⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inst.c

📁 Spim软件的一些源码。其中有Xspim的
💻 C
📖 第 1 页 / 共 3 页
字号:
/* SPIM S20 MIPS simulator.   Code to build assembly instructions and resolve symbolic labels.   Copyright (C) 1990-2004 by James Larus (larus@cs.wisc.edu).   ALL RIGHTS RESERVED.   SPIM is distributed under the following conditions:     You may make copies of SPIM for your own use and modify those copies.     All copies of SPIM must retain my name and copyright notice.     You may not sell SPIM or distributed SPIM in conjunction with a     commerical product or service without the expressed written consent of     James Larus.   THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR   IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR   PURPOSE. *//* $Header: /Software/SPIM/src/inst.c 27    10/19/04 9:22p Larus $*/#include <stdio.h>#include <string.h>#include "spim.h"#include "string-stream.h"#include "spim-utils.h"#include "inst.h"#include "reg.h"#include "mem.h"#include "sym-tbl.h"#include "parser.h"#include "scanner.h"#include "y.tab.h"#include "data.h"/* Local functions: */static int compare_pair_value (name_val_val *p1, name_val_val *p2);static void format_imm_expr (str_stream *ss, imm_expr *expr, int base_reg);static void i_type_inst_full_word (int opcode, int rt, int rs, imm_expr *expr,				   int value_known, int32 value);static void inst_cmp (instruction *inst1, instruction *inst2);static instruction *make_r_type_inst (int opcode, int rd, int rs, int rt);static instruction *mk_i_inst (int32 value, int opcode, int rs, int rt, int offset);static instruction *mk_j_inst (int32, int opcode, int target);static instruction *mk_r_inst (int32, int opcode, int rs, int rt, int rd, int shamt);static void produce_immediate (imm_expr *expr, int rt, int value_known, int32 value);static void sort_a_opcode_table ();static void sort_i_opcode_table ();static void sort_name_table ();/* Local variables: *//* Non-zero means store instructions in kernel, not user, text segment */static int in_kernel = 0;/* Instruction used as breakpoint by SPIM: */static instruction *break_inst = NULL;/* Locations for next instruction in user and kernel text segments */static mem_addr next_text_pc;static mem_addr next_k_text_pc;#define INST_PC (in_kernel ? next_k_text_pc : next_text_pc)#define BUMP_INST_PC(DELTA) {if (in_kernel) \			       next_k_text_pc += DELTA; \			       else next_text_pc += DELTA;}/* Set ADDRESS at which the next instruction is stored. */voidtext_begins_at_point (mem_addr addr){  next_text_pc = addr;}voidk_text_begins_at_point (mem_addr addr){  next_k_text_pc = addr;}/* Set the location (in user or kernel text space) for the next instruction. */voidset_text_pc (mem_addr addr){  if (in_kernel)    next_k_text_pc = addr;  else    next_text_pc = addr;}/* Return address for next instruction, in appropriate text segment. */mem_addrcurrent_text_pc (){  return (INST_PC);}/* Increment the current text segement PC. */voidincrement_text_pc (int delta){  BUMP_INST_PC (delta);}/* If FLAG is non-zero, next instruction goes to kernel text segment,   otherwise it goes to user segment. */voiduser_kernel_text_segment (int to_kernel){  in_kernel = to_kernel;}/* Store an INSTRUCTION in memory at the next location. */voidstore_instruction (instruction *inst){  if (data_dir)    {      store_word (inst_encode (inst));      free_inst (inst);    }  else if (text_dir)    {      exception_occurred = 0;      set_mem_inst (INST_PC, inst);      if (exception_occurred)	error ("Invalid address (0x%08x) for instruction\n", INST_PC);      else	BUMP_INST_PC (BYTES_PER_WORD);      if (inst != NULL)	{	  SET_SOURCE (inst, source_line ());	  if (ENCODING (inst) == 0)	    SET_ENCODING (inst, inst_encode (inst));	}    }}voidi_type_inst_free (int opcode, int rt, int rs, imm_expr *expr){  i_type_inst (opcode, rt, rs, expr);  free (expr);}/* Produce an immediate instruction with the OPCODE, RT, RS, and IMM   fields.  NB, because the immediate value may not fit in the field,   this routine may produce more than one instruction.	On the bare   machine, we resolve symbolic address, but they better produce values   that fit into instruction's immediate field. */voidi_type_inst (int opcode, int rt, int rs, imm_expr *expr){  instruction *inst = (instruction *) zmalloc (sizeof (instruction));  SET_OPCODE (inst, opcode);  SET_RS (inst, rs);  SET_RT (inst, rt);  SET_EXPR (inst, copy_imm_expr (expr));  if (expr->symbol == NULL || SYMBOL_IS_DEFINED (expr->symbol))    {      /* Evaluate the instruction's expression. */      int32 value = eval_imm_expr (expr);      if (!bare_machine	  && (((opcode == Y_ADDI_OP		|| opcode == Y_ADDIU_OP		|| opcode == Y_SLTI_OP		|| opcode == Y_SLTIU_OP)	       ? ((value & 0xffff8000) != 0		  && (value & 0xffff8000) != 0xffff8000)	       : (value & 0xffff0000) != 0)))	{	  free_inst (inst);	  i_type_inst_full_word (opcode, rt, rs, expr, 1, value);	  return;	}      else	resolve_a_label (expr->symbol, inst);    }  else if (bare_machine || expr->bits != 0)    /* Don't know expression's value, but only needed upper/lower 16-bits       anyways. */    record_inst_uses_symbol (inst, expr->symbol);  else    {      /* Don't know the expressions's value and want all of its bits,	 so assume that it will not produce a small result and generate	 sequence for 32 bit value. */      free_inst (inst);      i_type_inst_full_word (opcode, rt, rs, expr, 0, 0);      return;    }  store_instruction (inst);}/* The immediate value for an instruction will (or may) not fit in 16 bits.   Build the value from its piece with separate instructions. */static voidi_type_inst_full_word (int opcode, int rt, int rs, imm_expr *expr,		       int value_known, int32 value){  if (opcode_is_load_store (opcode))    {      int offset;      if (expr->symbol != NULL	  && expr->symbol->gp_flag	  && rs == 0	  && IMM_MIN <= (offset = expr->symbol->addr + expr->offset)	  && offset <= IMM_MAX)	{	  i_type_inst_free (opcode, rt, REG_GP, make_imm_expr (offset, NULL, 0));	}      else if (value_known)	{	  int low, high;	  high = (value >> 16) & 0xffff;	  low = value & 0xffff;	  if (high != 0 &&	      !(high == 0xffff && (low & 0x8000)))	    {	      /* Some of high 16 bits are non-zero */	      if (low & 0x8000)		{		  /* Adjust high 16, since load sign-extends low 16*/		  high += 1;		}	      i_type_inst_free (Y_LUI_OP, 1, 0, const_imm_expr (high));	      if (rs != 0)	/* Base register */		{		r_type_inst (Y_ADDU_OP, 1, 1, rs);		}	      i_type_inst_free (opcode, rt, 1, const_imm_expr (low));	    }	  else	    {	      /* Special case, sign-extension of low 16 bits sets high to 0xffff */	      i_type_inst_free (opcode, rt, rs, const_imm_expr (low));	    }	}      else	{	  /* Use $at */	  /* Need to adjust if lower bits are negative */	  i_type_inst_free (Y_LUI_OP, 1, 0, upper_bits_of_expr (expr));	  if (rs != 0)		/* Base register */	    {	    r_type_inst (Y_ADDU_OP, 1, 1, rs);	    }	  i_type_inst_free (opcode, rt, 1, lower_bits_of_expr (expr));	}    }  else if (opcode_is_branch (opcode))    {      /* This only allows branches +/- 32K, which is not correct! */      i_type_inst_free (opcode, rt, rs, lower_bits_of_expr (expr));    }  else    /* Computation instruction */    {      int offset;      if (expr->symbol != NULL	  && expr->symbol->gp_flag && rs == 0	  && IMM_MIN <= (offset = expr->symbol->addr + expr->offset)	  && offset <= IMM_MAX)	{	i_type_inst_free ((opcode == Y_LUI_OP ? Y_ADDIU_OP : opcode),			  rt, REG_GP, make_imm_expr (offset, NULL, 0));	}      else	{	  /* Use $at */	  if ((opcode == Y_ORI_OP	       || opcode == Y_ADDI_OP	       || opcode == Y_ADDIU_OP	       || opcode == Y_LUI_OP)	      && rs == 0)	    {	      produce_immediate(expr, rt, value_known, value);	    }	  else	    {	      produce_immediate(expr, 1, value_known, value);	      r_type_inst (imm_op_to_op (opcode), rt, rs, 1);	    }	}    }}static voidproduce_immediate (imm_expr *expr, int rt, int value_known, int32 value){  if (value_known && (value & 0xffff) == 0)    {      i_type_inst_free (Y_LUI_OP, rt, 0, upper_bits_of_expr (expr));    }  else if (value_known && (value & 0xffff0000) == 0)    {      i_type_inst_free (Y_ORI_OP, rt, 0, lower_bits_of_expr (expr));    }  else    {      i_type_inst_free (Y_LUI_OP, 1, 0, upper_bits_of_expr (expr));      i_type_inst_free (Y_ORI_OP, rt, 1, lower_bits_of_expr(expr));    }}/* Return a jump-type instruction with the given OPCODE and TARGET   fields. NB, even the immediate value may not fit in the field, this   routine will not produce more than one instruction. */voidj_type_inst (int opcode, imm_expr *target){  instruction *inst = (instruction *) zmalloc (sizeof (instruction));  SET_OPCODE(inst, opcode);  target->offset = 0;		/* Not PC relative */  target->pc_relative = 0;  SET_EXPR (inst, copy_imm_expr (target));  if (target->symbol == NULL || SYMBOL_IS_DEFINED (target->symbol))    resolve_a_label (target->symbol, inst);  else    record_inst_uses_symbol (inst, target->symbol);  store_instruction (inst);}/* Return a register-type instruction with the given OPCODE, RD, RS, and RT   fields. */static instruction *make_r_type_inst (int opcode, int rd, int rs, int rt){  instruction *inst = (instruction *) zmalloc (sizeof (instruction));  SET_OPCODE(inst, opcode);  SET_RS(inst, rs);  SET_RT(inst, rt);  SET_RD(inst, rd);  SHAMT(inst) = 0;  return (inst);}/* Return a register-type instruction with the given OPCODE, RD, RS, and RT   fields. */voidr_type_inst (int opcode, int rd, int rs, int rt){  store_instruction (make_r_type_inst (opcode, rd, rs, rt));}/* Return a register-type instruction with the given OPCODE, FD, FS, and FT   fields. */voidr_co_type_inst (int opcode, int fd, int fs, int ft){  instruction *inst = make_r_type_inst (opcode, fs, 0, ft);  SET_FD (inst, fd);  store_instruction (inst);}/* Return a register-shift instruction with the given OPCODE, RD, RT, and   SHAMT fields.*/voidr_sh_type_inst (int opcode, int rd, int rt, int shamt){  instruction *inst = make_r_type_inst (opcode, rd, 0, rt);  SET_SHAMT(inst, shamt & 0x1f);  store_instruction (inst);}/* Return a floating-point compare instruction with the given OPCODE,   FS, FT, and CC fields.*/voidr_cond_type_inst (int opcode, int fs, int ft, int cc){  instruction *inst = make_r_type_inst (opcode, fs, 0, ft);  SET_FD(inst, cc << 2);  switch (opcode)    {    case Y_C_EQ_D_OP:    case Y_C_EQ_S_OP:      {	SET_COND(inst, COND_EQ);	break;      }    case Y_C_LE_D_OP:    case Y_C_LE_S_OP:      {	SET_COND(inst, COND_IN | COND_LT | COND_EQ);	break;      }    case Y_C_LT_D_OP:    case Y_C_LT_S_OP:      {	SET_COND(inst, COND_IN | COND_LT);	break;      }    case Y_C_NGE_D_OP:    case Y_C_NGE_S_OP:      {	SET_COND(inst, COND_IN | COND_LT | COND_UN);	break;      }    case Y_C_NGLE_D_OP:    case Y_C_NGLE_S_OP:      {	SET_COND(inst, COND_IN | COND_UN);	break;      }    case Y_C_NGL_D_OP:    case Y_C_NGL_S_OP:      {	SET_COND(inst, COND_IN | COND_EQ | COND_UN);	break;      }    case Y_C_NGT_D_OP:    case Y_C_NGT_S_OP:      {	SET_COND(inst, COND_IN | COND_LT | COND_EQ | COND_UN);	break;      }    case Y_C_OLT_D_OP:    case Y_C_OLT_S_OP:      {	SET_COND(inst, COND_LT);	break;      }    case Y_C_OLE_D_OP:    case Y_C_OLE_S_OP:      {	SET_COND(inst, COND_LT | COND_EQ);	break;      }    case Y_C_SEQ_D_OP:    case Y_C_SEQ_S_OP:      {	SET_COND(inst, COND_IN | COND_EQ);	break;      }    case Y_C_SF_D_OP:    case Y_C_SF_S_OP:      {	SET_COND(inst, COND_IN);	break;      }    case Y_C_F_D_OP:    case Y_C_F_S_OP:      {	SET_COND(inst, 0);	break;      }    case Y_C_UEQ_D_OP:    case Y_C_UEQ_S_OP:      {	SET_COND(inst, COND_EQ | COND_UN);	break;      }    case Y_C_ULT_D_OP:    case Y_C_ULT_S_OP:      {	SET_COND(inst, COND_LT | COND_UN);	break;      }    case Y_C_ULE_D_OP:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -