translator.h 14.5 KB
/*
 * Copyright (C) 1996-1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * 
 * This file is part of the SimOS distribution. 
 * See LICENSE file for terms of the license. 
 *
 */

#ifndef TRANSLATOR_H
#define TRANSLATOR_H

#include "tc.h"

/* TRANSLATOR POLICY */

/* Barrier every basic block */
/*#define CHAIN_BAR_SYNC*/

/* Defining this has the dispatch loop print the current pc to stdout.  With NO_CHAINING*/
/* This prints the beginning of every basic block */
/* Presently it skips the slave loop (who wants to see that?) */
/*#define PRINT_PC*/


/* Enables recording  of translations */
/*#define RECORD_TRANSLATIONS*/

/* END TRANSLATOR POLICY */

/* All offsets are relative to the one above it */
/* This offset gets put in the pc_tc_lookup hash table.  It is the */
/* most conservative.  It checks virtual and physical address match */
/* (and so would be used by a jr) */

#ifdef OLDCODE

/* XXX ack! this doesn't work on vcode -BL */

#define SPECULATIVE_ENTRY ((embra.emode == EMBRA_PAGE)?5:4)

/* This is an offset relative to SPECULATIVE_ENTRY.  It assumes that */
/* the virtual address is correct, it just checks that the physical */
/* page we want is mapped (and so would be used by branches or jumps */
/* that span a page */
#define CHECK_MAPPING_ENTRY (3)

/* This is also an offset relative to CHECK_MAPPING_ENTRY.  It assumes */
/* that we know what virtual address we chained to, and it assumes */
/* that the physical page we are chaining to is mapped.  It is */
/* therefore appropriate for branches and jumps within a page */
#define SAME_PAGE_ENTRY (embra.MPinUP?7:5)


#endif


/* This is used by CP0 instructions that can except, and that have no */
/* special parameters (like the move to/from ) */
#ifdef OLDCODE
#define DO_CALLOUT_LEN (6)
#else
#define DO_CALLOUT_LEN (6)
#endif

#ifndef _LANGUAGE_ASSEMBLY
void Translator_Init(void);
/* Both are called from continue_run */
C_LINK TCA Translate( int cpuNum, VA current_pc, int* has_flushed );
C_LINK TCA ChainBasicBlock(TCA jump_addr,VA new_pc);

C_LINK void CountFP(void);

extern TCA Get_TCA_No_Icache_Check( int cpuNum, VA vAddr );



/* ***************************************************************
 * Code emission macros
 * ***************************************************************/

/* vcode versions of code emission macros */

/* shifts */

#define ECsh(funct, _rd, _rt, shamt) prev_store.real=0; \
				VC_ ## funct(VREGS[_rd], VREGS[_rt], \
						shamt)
#define VC_srl_op_(_rd, _rt, shamt) v_rshui(_rd, _rt, shamt)
#define VC_sra_op_(_rd, _rt, shamt) v_rshii(_rd, _rt, shamt)
#define VC_sll_op_(_rd, _rt, shamt) v_lshui(_rd, _rt, shamt)

/* arithmetic functions */
#define ECs(funct, _rd, _rs, _rt)  prev_store.real=0; \
				  VC_ ## funct(VREGS[_rd],VREGS[_rs], \
						VREGS[_rt])
				  
#define VC_add_op_(_rd, _rs, _rt)   v_addi(_rd, _rs, _rt)
#define VC_addi_op_(_rd, _rs, _immed)  v_addii(_rd, _rs, _immed)
#define VC_addu_op_(_rd, _rs, _rt)  v_addu(_rd, _rs, _rt)
#define VC_and_op_(_rd, _rs, _rt)   v_andu(_rd, _rs, _rt)
#define VC_andi_op_(_rd, _rs, _immed)  v_andusi(_rd, _rs, (unsigned short) _immed)
#define VC_jr_op_(_rd, _rs, _rt)    v_jp(_rs)

/* XXX this is cheesoid; should be more elegant... */
#if defined(SIM_MIPS32)
#define VC_mult_op_(_rd, _rs, _rt)  {   v_mulhii(_rd, _rs, _rt); \
					v_stui(_rd, VREGS[VSS_BASE], HI_OFF); \
					v_muli(_rd, _rs, _rt); \
					v_stui(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_multu_op_(_rd, _rs, _rt)  {   v_mulhiu(_rd, _rs, _rt); \
					v_stui(_rd, VREGS[VSS_BASE], HI_OFF); \
					v_mulu(_rd, _rs, _rt); \
					v_stui(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_div_op_(_rd, _rs, _rt)   { v_modi(_rd, _rs, _rt); \
				      v_stui(_rd, VREGS[VSS_BASE], HI_OFF); \
				      v_divi(_rd, _rs, _rt); \
				      v_stui(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_divu_op_(_rd, _rs, _rt)  { v_modu(_rd, _rs, _rt); \
				      v_stui(_rd, VREGS[VSS_BASE], HI_OFF); \
				      v_divu(_rd, _rs, _rt); \
				      v_stui(_rd, VREGS[VSS_BASE], LO_OFF); }
#else
#define VC_mult_op_(_rd, _rs, _rt)  {   v_mulhii(_rd, _rs, _rt); \
					v_stli(_rd, VREGS[VSS_BASE], HI_OFF); \
					v_muli(_rd, _rs, _rt); \
					v_stli(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_multu_op_(_rd, _rs, _rt)  {   v_mulhiu(_rd, _rs, _rt); \
					v_stli(_rd, VREGS[VSS_BASE], HI_OFF); \
					v_mulu(_rd, _rs, _rt); \
					v_stli(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_div_op_(_rd, _rs, _rt)   { v_modi(_rd, _rs, _rt); \
				      v_stli(_rd, VREGS[VSS_BASE], HI_OFF); \
				      v_divi(_rd, _rs, _rt); \
				      v_stli(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_divu_op_(_rd, _rs, _rt)  { v_modu(_rd, _rs, _rt); \
				      v_stli(_rd, VREGS[VSS_BASE], HI_OFF); \
				      v_divu(_rd, _rs, _rt); \
				      v_stli(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_dmult_op_(_rd, _rs, _rt)  {   v_mulhil(_rd, _rs, _rt); \
					v_stli(_rd, VREGS[VSS_BASE], HI_OFF); \
					v_mull(_rd, _rs, _rt); \
					v_stli(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_dmultu_op_(_rd, _rs, _rt)  {   v_mulhiul(_rd, _rs, _rt); \
					v_stli(_rd, VREGS[VSS_BASE], HI_OFF); \
					v_mulul(_rd, _rs, _rt); \
					v_stli(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_ddiv_op_(_rd, _rs, _rt)   { v_modl(_rd, _rs, _rt); \
				      v_stli(_rd, VREGS[VSS_BASE], HI_OFF); \
				      v_divul(_rd, _rs, _rt); \
				      v_stli(_rd, VREGS[VSS_BASE], LO_OFF); }
#define VC_ddivu_op_(_rd, _rs, _rt)  { v_modul(_rd, _rs, _rt); \
				      v_stli(_rd, VREGS[VSS_BASE], HI_OFF); \
				      v_divul(_rd, _rs, _rt); \
				      v_stli(_rd, VREGS[VSS_BASE], LO_OFF); }
#endif

#define VC_nor_op_(_rd, _rs, _rt)   v_noru(_rd, _rs, _rt)
#define VC_or_op_(_rd, _rs, _rt)    v_oru(_rd, _rs, _rt)
#define VC_sllv_op_(_rd, _rs, _rt)  v_lshu(_rd, _rt, _rs)
#define VC_slt_op_(_rd, _rs, _rt)   v_lti(_rd, _rs, _rt)
#define VC_slti_op_(_rd, _rs, _immed)   v_ltii(_rd, _rs, _immed)
#define VC_sltiu_op_(_rd, _rs, _immed)   v_ltui(_rd, _rs, _immed)
#define VC_sltu_op_(_rd, _rs, _rt)  v_ltu(_rd, _rs, _rt)
#define VC_srav_op_(_rd, _rs, _rt)  v_rshi(_rd, _rt, _rs)
#define VC_srlv_op_(_rd, _rs, _rt)  v_rshu(_rd, _rt, _rs)
#define VC_sub_op_(_rd, _rs, _rt)   v_subi(_rd, _rs, _rt)
#define VC_subu_op_(_rd, _rs, _rt)  v_subu(_rd, _rs, _rt)
#define VC_xor_op_(_rd, _rs, _rt)   v_xoru(_rd, _rs, _rt)
#define VC_xori_op_(_rd, _rs, _immed)   v_xorusi(_rd, _rs, \
						 (unsigned short) _immed)

/* branches  - note we only support one label deep!!
 * note also that you MUST follow a branch with a
 * VCTARGET (i.e. v_label(label)) at the appropriate point in the instruction
 * stream!!
 */
#define ECb(funct, _rs, offset) {prev_store.real=0;label = v_genlabel(); \
					VC_ ## funct(_rs, offset);}
#define VC_bltz_op_(_rs, offset) v_bltii(VREGS[_rs], 0, label) 
#define VCTARGET  v_label(label)

#define SET_LABEL(_lab) {labels._lab = v_genlabel(); v_label(labels._lab); \
			 labels._lab##_addr = v_ip;}

/* This says, subtract the two TC addresses and subtract 1 for the */
/* instruction I am in */
#define USE_LABEL(_lab) _lab
#define USE_LABEL_VALUE(_lab) _lab

/* immediate-mode instructions */
#define ECi(opcode, _rt, _rs, _immed) {prev_store.real=0; \
				VC_ ## opcode(VREGS[_rt], VREGS[_rs], \
					      _immed);}
#define ECilab(opcode, _rt, _rs, _label) {prev_store.real=0; \
				  VCL_ ## opcode(VREGS[_rt], \
						 VREGS[_rs], _label);}
  
#define EC1i(opcode, _rt, _rs, _immed) {prev_store.real=0; \
				  VC_ ## opcode(FVREGS[_rt],VREGS[_rs], \
						_immed);}
#define VC_andiu_op_(_rt, _rs, _immed) v_andusi(_rt, _rs, (unsigned short) _immed)
#define VC_addiu_op_(_rt, _rs, _immed) v_addui(_rt, _rs, _immed)
#define VCL_addiu_op_(_rt, _rs, _label) v_addui(_rt, _rs, \
		 ((unsigned long) (v_ip - (labels. ## _label ## _addr))))
#define VC_bne_op_(_rt, _rs, _immed) {label = v_genlabel(); \
					v_bnei(_rs, _rt, label);}
#define VCL_bne_op_(_rt, _rs, _label) v_bnei(_rs, _rt, labels. ## _label)
#define VC_beq_op_(_rt, _rs, _immed) {label = v_genlabel(); \
					v_beqi(_rs, _rt, label);}
#define VC_blez_op_(_rt, _rs, _immed) {label = v_genlabel(); \
					v_bleii(_rs, 0, label);}
#define VCL_blez_op_(_rt, _rs, _label) 	v_bleii(_rs, 0, (labels. ## _label))
#define VC_bgez_op_(_rs, _immed) {label = v_genlabel(); \
					v_bgeii(VREGS[_rs], 0, label);}
#define VC_bgtz_op_(_rt, _rs, _immed) {label = v_genlabel();\
				v_bgtii(_rs, 0, label);}
#define VC_ori_op_(_rt, _rs, _immed) v_orusi(_rt, _rs, (unsigned short) (_immed))
#define VC_lw_op_(_rt, _rs, _immed) v_ldui(_rt, _rs, _immed)
#define VC_lwc1_op_(_rt, _rs, _immed) v_ldfi(_rt, _rs, _immed)

#ifdef SIM_MIPS64
/* XXX THIS STILL WON'T WORK -BL */
#define VC_ldc1_op_(_rt, _rs, _immed) dldc1((_rt).reg,(_rs).reg, _immed)
#else
#define VC_ldc1_op_(_rt, _rs, _immed) v_lddi(_rt, _rs, _immed)
#endif

/** this is inefficient; probably can make one of these a NOP -BL */
/* #define VC_lwl_op_(_rt, _rs, _immed) v_uldui(_rt, _rs, _immed) */
/* #define VC_lwr_op_(_rt, _rs, _immed) v_uldui(_rt, _rs, _immed) */
#define VC_lwl_op_(_rt, _rs, _immed) lwl((_rt).reg, (_rs).reg, _immed)
#define VC_lwr_op_(_rt, _rs, _immed) lwr((_rt).reg, (_rs).reg, _immed)
#define VC_ldl_op_(_rt, _rs, _immed) ldl((_rt).reg, (_rs).reg, _immed)
#define VC_ldr_op_(_rt, _rs, _immed) ldr((_rt).reg, (_rs).reg, _immed)

/** ugh!! we're hosed on these operations. Need to fix this!!! */
/* #define VC_swl_op_(_rt, _rs, _immed) v_ustui(_rt, _rs, _immed)
   #define VC_swr_op_(_rt, _rs, _immed) v_ustui(_rt, _rs, _immed)
   right now, an ugly hack.... XXX -BL
*/
#define VC_swl_op_(_rt, _rs, _immed) swl((_rt).reg, (_rs).reg, _immed)
#define VC_swr_op_(_rt, _rs, _immed) swr((_rt).reg, (_rs).reg, _immed)
#define VC_sdl_op_(_rt, _rs, _immed) sdl((_rt).reg, (_rs).reg, _immed)
#define VC_sdr_op_(_rt, _rs, _immed) sdr((_rt).reg, (_rs).reg, _immed)

#define VC_lui_op_(_rt, _rs, _immed) v_seti(_rt,((_immed)<<16 & 0xffff0000))
#define VC_sw_op_(_rt, _rs, _immed) v_stui(_rt, _rs, _immed)
#define VC_swc1_op_(_rt, _rs, _immed) v_stfi(_rt, _rs, _immed)
#ifdef SIM_MIPS64
/* XXX THIS STILL WON'T WORK -BL */
#define VC_sdc1_op_(_rt, _rs, _immed) dsdc1((_rt).reg, (_rs).reg, _immed)
#else
#define VC_sdc1_op_(_rt, _rs, _immed) v_stdi(_rt, _rs, _immed)
#endif
#define VC_lb_op_(_rt, _rs, _immed) v_ldci(_rt, _rs, _immed)
#define VC_sb_op_(_rt, _rs, _immed) v_stci(_rt, _rs, _immed)
#define VC_lbu_op_(_rt, _rs, _immed) v_lduci(_rt, _rs, _immed)
#define VC_lh_op_(_rt, _rs, _immed) v_ldsi(_rt, _rs, _immed)
#define VC_sh_op_(_rt, _rs, _immed) v_stsi(_rt, _rs, _immed)
#define VC_lhu_op_(_rt, _rs, _immed) v_ldusi(_rt, _rs, _immed)
/** XXX another ugly hack for now; need to implement in vcode  -BL */
#define VC_lwu_op_(_rt, _rs, _immed) { v_ldui(_rt, _rs, _immed); \
				dsll32((_rt).reg, (_rt).reg, 0); \
				dsrl32((_rt).reg, (_rt).reg, 0); \
				}

/* note we only support one label deep */

/* jumps */
#define ECj(opcode, target) prev_store.real=0; VC_ ## opcode(target)
/* XXX this is a disgusting hack to make vcode generate a plain old
* jal using r31; need a better way to do this -BL
* should be:  v_jalpi(_ra,target), if we had ra
* this WILL NOT WORK on sparc, etc. - need to fix
*/
#define VC_jal_op_(target) {prev_store.real=0; jal((unsigned)target);v_nop();}

#define VC_j_op_(target) {prev_store.real = 0; v_jpi(target);}

/* nop */
#define ECnop {prev_store.real = 0; } /* was v_nop(); */

/* more immediates */

#define ECImmed(_op1, _op2, _rs, _immed) prev_store.real=0; \
				VC_ ## _op1 ## _op2(_rs, _immed)

/* Coprocessor instructions */

/* cop1move: move between integer register and fp data/control registers */
#define ECCop1Move(_inst, _rt, _fs) VC_ ## _inst(_rt, _fs)
				  
/* RPB -- I changed these to be analogous to mtc/mfc below */
#define VC_ctc_op_(_rt, _fs) { prev_store.real=0; ctc1(_fs, _rt); }
#define VC_cfc_op_(_rt, _fs) { prev_store.real=0; cfc1(_rt, _fs); }

/* XXX right now, this is efficient but non-portable; for SPARC add
 * new vcode operation?? or just go through memory? 
 */
#define VC_mtc_op_(_rt, _fs) { prev_store.real=0; movi2f(_fs, _rt); }
#define VC_mfc_op_(_rt, _fs) { prev_store.real=0; movf2i(_rt, _fs); }
#define VC_dmtc_op_(_rt, _fs) { prev_store.real=0; dmtc1(_fs, _rt); }
#define VC_dmfc_op_(_rt, _fs) { prev_store.real=0; dmfc1(_rt, _fs); }


/* Generate MIPS instructions - CHEESOID!! Yes, we have to
 * do this, at least right now!! -BL
 */
#define VC_ComposeBCOND(rs,funct,offset) (prev_store.real = 0, (int)\
(bcond_op << 26 | (rs) << 21 | (funct) << 16 | ((offset) & 0xffff ) ) )

#define VC_ComposeImmed(opCode,rs,rt,immed) (prev_store.real = 0, (int)\
 ((opCode) << 26 | (rs) << 21 | (rt) << 16 | ((uint)(immed) & 0xffff ) ) )



/* temporary hack to test whether chaining is totally hosed */
#define ComposeJump(opCode,target) (prev_store.real = 0, (int)\
                             ((opCode) << 26 |((uint)(target) & 0x3ffffff ) ) )
     
#if defined(SIM_MIPS64)

/* 64-bit instructions */

#define VC_dsll_op_(_rd, _rs, _rt)    v_lshli(_rd, _rs, _rt)
#define VC_dsll32_op_(_rd, _rs, _imm) dsll32(_rd.reg, _rs.reg, _imm)
#define VC_dsrl_op_(_rd, _rs, _imm)   v_rshuli(_rd, _rs, _imm)
#define VC_dsra_op_(_rd, _rs, _imm)   v_rshli(_rd, _rs, _imm)
#define VC_dsra32_op_(_rd, _rs, _imm) dsra32(_rd.reg, _rs.reg, _imm)
#define VC_dsrl32_op_(_rd, _rs, _imm) dsrl32(_rd.reg, _rs.reg, _imm)
#define VC_dadd_op_(_rd, _rs, _rt)    v_addl(_rd, _rs, _rt)
#define VC_daddu_op_(_rd, _rs, _rt)   v_addul(_rd, _rs, _rt)
#define VC_dsllv_op_(_rd, _rs, _rt)   v_lshl(_rd, _rs, _rt)
#define VC_dsrlv_op_(_rd, _rs, _rt)   v_rshul(_rd, _rs, _rt)
#define VC_dsrav_op_(_rd, _rs, _rt)   v_rshl(_rd, _rs, _rt)
#define VC_dsub_op_(_rd, _rs, _rt)    v_subl(_rd, _rs, _rt)
#define VC_dsubu_op_(_rd, _rs, _rt)   v_subul(_rd, _rs, _rt)
#define VC_daddi_op_(_rd, _rs, _rt)    v_addli(_rd, _rs, _rt)
#define VC_daddiu_op_(_rd, _rs, _rt)   v_adduli(_rd, _rs, _rt)

#define VC_ld_op_(_rt, _rs, _immed) v_ldli(_rt, _rs, _immed)
#define VC_sd_op_(_rt, _rs, _immed) v_stli(_rt, _rs, _immed)

#endif

/* allow vcode to do this for us */

#define VCL_lw_op_(_reg, _addr) {Load_32_Bit_Immed (_reg, _addr); \
					v_ldui(VREGS[_reg], VREGS[_reg], 0);}
#define VCL_ld_op_(_reg, _addr) {Load_32_Bit_Immed (_reg, _addr); \
					v_ldli(VREGS[_reg], VREGS[_reg], 0);}
#define VCL_lb_op_(_reg, _addr) {Load_32_Bit_Immed(_reg, _addr); \
					v_ldci(VREGS[_reg], VREGS[_reg], 0);}
/* Convenience Functions (glorified macros) */
#define Load_32_Bit_Immed(_reg, _immed){prev_store.real=0; \
			v_seti(VREGS[_reg],(_immed) & 0xffff0000); \
					v_orii(VREGS[_reg], VREGS[_reg], \
					       (_immed) & 0xffff);}
/*  #define Load_64_Bit_Immed(_reg, _immed){prev_store.real=0; \
				v_setl(VREGS[_reg],(_immed));} */

#if defined(SIM_MIPS32)
#define Load_Reg_Immed Load_32_Bit_Immed
#endif


#endif /*_LANGUAGE_ASSEMBLY */
#endif /* TRANSLATOR_H */