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

📄 inst.c

📁 用汇编语言编程源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* SPIM S20 MIPS simulator.   Code to build assembly instructions and resolve symbolic labels.   Copyright (C) 1990-2000 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 10    12/24/00 1:37p Larus $*/#include <stdio.h>#include <string.h>#include "spim.h"#include "spim-utils.h"#include "inst.h"#include "mem.h"#include "reg.h"#include "sym-tbl.h"#include "parser.h"#include "scanner.h"#include "y.tab.h"#include "data.h"/* Local functions: */#ifdef __STDC__static int compare_pair_value (inst_info *p1, inst_info *p2);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 (uint32 value, int opcode, int rs,			       int rt, int offset);static instruction *mk_j_inst (uint32, int opcode, int target);static instruction *mk_r_inst (uint32, int opcode, int rs,			       int rt, int rd, int shamt);static char* print_imm_expr (char *buf, unsigned int length, imm_expr *expr,			     int base_reg);static void produce_immediate (imm_expr *expr, int rt, int value_known, int32 value);static void sort_name_table (void);#elsestatic int compare_pair_value ();static void i_type_inst_f ();static void i_type_inst_full_word ();static void inst_cmp ();static instruction * make_r_type_inst ();static instruction *mk_i_inst ();static instruction *mk_j_inst ();static instruction *mk_r_inst ();static char* print_imm_expr ();static void produce_immediate ();static void sort_name_table ();#endif/* 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. */#ifdef __STDC__voidtext_begins_at_point (mem_addr addr)#elsevoidtext_begins_at_point (addr)     mem_addr addr;#endif{  next_text_pc = addr;}#ifdef __STDC__voidk_text_begins_at_point (mem_addr addr)#elsevoidk_text_begins_at_point (addr)     mem_addr addr;#endif{  next_k_text_pc = addr;}/* Set the location (in user or kernel text space) for the next instruction. */#ifdef __STDC__voidset_text_pc (mem_addr addr)#elsevoidset_text_pc (addr)     mem_addr addr;#endif{  if (in_kernel)    next_k_text_pc = addr;  else    next_text_pc = addr;}/* Return address for next instruction, in appropriate text segment. */#ifdef __STDC__mem_addrcurrent_text_pc (void)#elsemem_addrcurrent_text_pc ()#endif{  return (INST_PC);}/* Increment the current text segement PC. */#ifdef __STDC__voidincrement_text_pc (int delta)#elsevoidincrement_text_pc (delta)     int delta;#endif{  BUMP_INST_PC (delta);}/* If FLAG is non-zero, next instruction goes to kernel text segment,   otherwise it goes to user segment. */#ifdef __STDC__voiduser_kernel_text_segment (int to_kernel)#elsevoiduser_kernel_text_segment (to_kernel)     int to_kernel;#endif{  in_kernel = to_kernel;}/* Store an INSTRUCTION in memory at the next location. */#ifdef __STDC__voidstore_instruction (instruction *inst)#elsevoidstore_instruction (inst)     instruction *inst;#endif{  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));	}    }}#ifdef __STDC__voidi_type_inst_free (int opcode, int rt, int rs, imm_expr *expr)#elsevoidi_type_inst_free (opcode, rt, rs, expr)     int opcode, rt, rs;     imm_expr *expr;#endif{  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. */#ifdef __STDC__voidi_type_inst (int opcode, int rt, int rs, imm_expr *expr)#elsevoidi_type_inst (opcode, rt, rs, expr)     int opcode, rt, rs;     imm_expr *expr;#endif{  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. */#ifdef __STDC__static voidi_type_inst_full_word (int opcode, int rt, int rs, imm_expr *expr,		       int value_known, int32 value)#elsestatic voidi_type_inst_full_word (opcode, rt, rs, expr, value_known, value)     int opcode, rt, rs;     imm_expr *expr;     int value_known;     int32 value;#endif{  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);	    }	}    }}#ifdef __STDC__static voidproduce_immediate (imm_expr *expr, int rt, int value_known, int32 value)#elsestatic voidproduce_immediate (expr, rt, value_known, value)     imm_expr *expr;     int rt;     int value_known;     int32 value;#endif{  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. */#ifdef __STDC__voidj_type_inst (int opcode, imm_expr *target)#elsevoidj_type_inst (opcode, target)     int opcode;     imm_expr *target;#endif{  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. */#ifdef __STDC__static instruction *make_r_type_inst (int opcode, int rd, int rs, int rt)#elsestatic instruction *make_r_type_inst (opcode, rd, rs, rt)     int opcode, rd, rs, rt;#endif{  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. */#ifdef __STDC__voidr_type_inst (int opcode, int rd, int rs, int rt)#elsevoidr_type_inst (opcode, rd, rs, rt)     int opcode, rd, rs, rt;#endif{  store_instruction (make_r_type_inst (opcode, rd, rs, rt));}/* Return a register-shift instruction with the given OPCODE, RD, RT, and   SHAMT fields.*/#ifdef __STDC__voidr_sh_type_inst (int opcode, int rd, int rt, int shamt)#elsevoidr_sh_type_inst (opcode, rd, rt, shamt)     int opcode, rd, rt, shamt;#endif{  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, and FT fields.*/#ifdef __STDC__voidr_cond_type_inst (int opcode, int rs, int rt)#elsevoidr_cond_type_inst (opcode, rs, rt)     int opcode, rs, rt;#endif{  instruction *inst = make_r_type_inst (opcode, 0, rs, rt);  switch (opcode)    {    case Y_C_EQ_D_OP:    case Y_C_EQ_S_OP:      {	COND(inst) = COND_EQ;	break;      }    case Y_C_LE_D_OP:    case Y_C_LE_S_OP:      {	COND(inst) = COND_IN | COND_LT | COND_EQ;	break;      }    case Y_C_LT_D_OP:    case Y_C_LT_S_OP:      {	COND(inst) = COND_IN | COND_LT;	break;      }    case Y_C_NGE_D_OP:    case Y_C_NGE_S_OP:      {	COND(inst) = COND_IN | COND_LT | COND_UN;	break;      }    case Y_C_NGLE_D_OP:    case Y_C_NGLE_S_OP:      {	COND(inst) = COND_IN | COND_UN;	break;      }    case Y_C_NGL_D_OP:    case Y_C_NGL_S_OP:      {	COND(inst) = COND_IN | COND_EQ | COND_UN;	break;      }    case Y_C_NGT_D_OP:    case Y_C_NGT_S_OP:      {	COND(inst) = COND_IN | COND_LT | COND_EQ | COND_UN;	break;      }    case Y_C_OLT_D_OP:    case Y_C_OLT_S_OP:      {	COND(inst) = COND_LT;	break;      }    case Y_C_OLE_D_OP:    case Y_C_OLE_S_OP:      {	COND(inst) = COND_LT | COND_EQ;	break;      }    case Y_C_SEQ_D_OP:    case Y_C_SEQ_S_OP:      {	COND(inst) = COND_IN | COND_EQ;	break;      }    case Y_C_SF_D_OP:    case Y_C_SF_S_OP:      {	COND(inst) = COND_IN;	break;      }    case Y_C_F_D_OP:    case Y_C_F_S_OP:      {	COND(inst) = 0;	break;      }    case Y_C_UEQ_D_OP:    case Y_C_UEQ_S_OP:      {	COND(inst) = COND_EQ | COND_UN;	break;      }    case Y_C_ULT_D_OP:    case Y_C_ULT_S_OP:      {	COND(inst) = COND_LT | COND_UN;	break;      }    case Y_C_ULE_D_OP:    case Y_C_ULE_S_OP:      {

⌨️ 快捷键说明

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