2021-02-06 09:39:32 +01:00
/*
* Copyright ( C ) 2002 - 2011 The DOSBox Team
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
/* MIPS32 (little endian) backend by crazyc */
// some configuring defines that specify the capabilities of this architecture
// or aspects of the recompiling
// protect FC_ADDR over function calls if necessaray
// #define DRC_PROTECT_ADDR_REG
// try to use non-flags generating functions if possible
# define DRC_FLAGS_INVALIDATION
// try to replace _simple functions by code
# define DRC_FLAGS_INVALIDATION_DCODE
// type with the same size as a pointer
# define DRC_PTR_SIZE_IM Bit32u
// calling convention modifier
# define DRC_CALL_CONV /* nothing */
# define DRC_FC /* nothing */
// use FC_REGS_ADDR to hold the address of "cpu_regs" and to access it using FC_REGS_ADDR
//#define DRC_USE_REGS_ADDR
// use FC_SEGS_ADDR to hold the address of "Segs" and to access it using FC_SEGS_ADDR
//#define DRC_USE_SEGS_ADDR
// register mapping
typedef Bit8u HostReg ;
# define HOST_v0 2
# define HOST_v1 3
# define HOST_a0 4
# define HOST_a1 5
# define HOST_t4 12
# define HOST_t5 13
# define HOST_t6 14
# define HOST_t7 15
# define HOST_s0 16
# define HOST_t8 24
# define HOST_t9 25
# define temp1 HOST_v1
# define temp2 HOST_t9
// register that holds function return values
# define FC_RETOP HOST_v0
// register used for address calculations,
# define FC_ADDR HOST_s0 // has to be saved across calls, see DRC_PROTECT_ADDR_REG
// register that holds the first parameter
# define FC_OP1 HOST_a0
// register that holds the second parameter
# define FC_OP2 HOST_a1
// special register that holds the third parameter for _R3 calls (byte accessible)
# define FC_OP3 HOST_???
// register that holds byte-accessible temporary values
# define FC_TMP_BA1 HOST_t5
// register that holds byte-accessible temporary values
# define FC_TMP_BA2 HOST_t6
// temporary register for LEA
# define TEMP_REG_DRC HOST_t7
# ifdef DRC_USE_REGS_ADDR
// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code
# define FC_REGS_ADDR HOST_???
# endif
# ifdef DRC_USE_SEGS_ADDR
// used to hold the address of "Segs" - preferably filled in function gen_run_code
# define FC_SEGS_ADDR HOST_???
# endif
// save some state to improve code gen
static bool temp1_valid = false ;
static Bit32u temp1_value ;
// move a full register from reg_src to reg_dst
static void gen_mov_regs ( HostReg reg_dst , HostReg reg_src ) {
if ( reg_src = = reg_dst ) return ;
cache_addw ( ( reg_dst < < 11 ) + 0x21 ) ; // addu reg_dst, $0, reg_src
cache_addw ( reg_src ) ;
}
// move a 32bit constant value into dest_reg
static void gen_mov_dword_to_reg_imm ( HostReg dest_reg , Bit32u imm ) {
if ( imm < 65536 ) {
cache_addw ( ( Bit16u ) imm ) ; // ori dest_reg, $0, imm
cache_addw ( 0x3400 + dest_reg ) ;
} else if ( ( ( Bit32s ) imm < 0 ) & & ( ( Bit32s ) imm > = - 32768 ) ) {
cache_addw ( ( Bit16u ) imm ) ; // addiu dest_reg, $0, imm
cache_addw ( 0x2400 + dest_reg ) ;
} else if ( ! ( imm & 0xffff ) ) {
cache_addw ( ( Bit16u ) ( imm > > 16 ) ) ; // lui dest_reg, %hi(imm)
cache_addw ( 0x3c00 + dest_reg ) ;
} else {
cache_addw ( ( Bit16u ) ( imm > > 16 ) ) ; // lui dest_reg, %hi(imm)
cache_addw ( 0x3c00 + dest_reg ) ;
cache_addw ( ( Bit16u ) imm ) ; // ori dest_reg, dest_reg, %lo(imm)
cache_addw ( 0x3400 + ( dest_reg < < 5 ) + dest_reg ) ;
}
}
// this is the only place temp1 should be modified
static void INLINE mov_imm_to_temp1 ( Bit32u imm ) {
if ( temp1_valid & & ( temp1_value = = imm ) ) return ;
gen_mov_dword_to_reg_imm ( temp1 , imm ) ;
temp1_valid = true ;
temp1_value = imm ;
}
static Bit16s gen_addr_temp1 ( Bit32u addr ) {
Bit32u hihalf = addr & 0xffff0000 ;
Bit16s lohalf = addr & 0xffff ;
if ( lohalf > 32764 ) { // [l,s]wl will overflow
hihalf = addr ;
lohalf = 0 ;
} else if ( lohalf < 0 ) hihalf + = 0x10000 ;
mov_imm_to_temp1 ( hihalf ) ;
return lohalf ;
}
// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
// 16bit moves may destroy the upper 16bit of the destination register
static void gen_mov_word_to_reg ( HostReg dest_reg , void * data , bool dword ) {
Bit16s lohalf = gen_addr_temp1 ( ( Bit32u ) data ) ;
// alignment....
if ( dword ) {
if ( ( Bit32u ) data & 3 ) {
cache_addw ( lohalf + 3 ) ; // lwl dest_reg, 3(temp1)
cache_addw ( 0x8800 + ( temp1 < < 5 ) + dest_reg ) ;
cache_addw ( lohalf ) ; // lwr dest_reg, 0(temp1)
cache_addw ( 0x9800 + ( temp1 < < 5 ) + dest_reg ) ;
} else {
cache_addw ( lohalf ) ; // lw dest_reg, 0(temp1)
cache_addw ( 0x8C00 + ( temp1 < < 5 ) + dest_reg ) ;
}
} else {
if ( ( Bit32u ) data & 1 ) {
cache_addw ( lohalf ) ; // lbu dest_reg, 0(temp1)
cache_addw ( 0x9000 + ( temp1 < < 5 ) + dest_reg ) ;
cache_addw ( lohalf + 1 ) ; // lbu temp2, 1(temp1)
cache_addw ( 0x9000 + ( temp1 < < 5 ) + temp2 ) ;
# if (_MIPS_ISA==MIPS32R2) || defined(PSP)
cache_addw ( 0x7a04 ) ; // ins dest_reg, temp2, 8, 8
cache_addw ( 0x7c00 + ( temp2 < < 5 ) + dest_reg ) ;
# else
cache_addw ( ( temp2 < < 11 ) + 0x200 ) ; // sll temp2, temp2, 8
cache_addw ( temp2 ) ;
cache_addw ( ( dest_reg < < 11 ) + 0x25 ) ; // or dest_reg, temp2, dest_reg
cache_addw ( ( temp2 < < 5 ) + dest_reg ) ;
# endif
} else {
cache_addw ( lohalf ) ; // lhu dest_reg, 0(temp1);
cache_addw ( 0x9400 + ( temp1 < < 5 ) + dest_reg ) ;
}
}
}
// move a 16bit constant value into dest_reg
// the upper 16bit of the destination register may be destroyed
static void gen_mov_word_to_reg_imm ( HostReg dest_reg , Bit16u imm ) {
cache_addw ( imm ) ; // ori dest_reg, $0, imm
cache_addw ( 0x3400 + dest_reg ) ;
}
// move 32bit (dword==true) or 16bit (dword==false) of a register into memory
static void gen_mov_word_from_reg ( HostReg src_reg , void * dest , bool dword ) {
Bit16s lohalf = gen_addr_temp1 ( ( Bit32u ) dest ) ;
// alignment....
if ( dword ) {
if ( ( Bit32u ) dest & 3 ) {
cache_addw ( lohalf + 3 ) ; // swl src_reg, 3(temp1)
cache_addw ( 0xA800 + ( temp1 < < 5 ) + src_reg ) ;
cache_addw ( lohalf ) ; // swr src_reg, 0(temp1)
cache_addw ( 0xB800 + ( temp1 < < 5 ) + src_reg ) ;
} else {
cache_addw ( lohalf ) ; // sw src_reg, 0(temp1)
cache_addw ( 0xAC00 + ( temp1 < < 5 ) + src_reg ) ;
}
} else {
if ( ( Bit32u ) dest & 1 ) {
cache_addw ( lohalf ) ; // sb src_reg, 0(temp1)
cache_addw ( 0xA000 + ( temp1 < < 5 ) + src_reg ) ;
cache_addw ( ( temp2 < < 11 ) + 0x202 ) ; // srl temp2, src_reg, 8
cache_addw ( src_reg ) ;
cache_addw ( lohalf + 1 ) ; // sb temp2, 1(temp1)
cache_addw ( 0xA000 + ( temp1 < < 5 ) + temp2 ) ;
} else {
cache_addw ( lohalf ) ; // sh src_reg, 0(temp1);
cache_addw ( 0xA400 + ( temp1 < < 5 ) + src_reg ) ;
}
}
}
// move an 8bit value from memory into dest_reg
// the upper 24bit of the destination register can be destroyed
// this function does not use FC_OP1/FC_OP2 as dest_reg as these
// registers might not be directly byte-accessible on some architectures
static void gen_mov_byte_to_reg_low ( HostReg dest_reg , void * data ) {
Bit16s lohalf = gen_addr_temp1 ( ( Bit32u ) data ) ;
cache_addw ( lohalf ) ; // lbu dest_reg, 0(temp1)
cache_addw ( 0x9000 + ( temp1 < < 5 ) + dest_reg ) ;
}
// move an 8bit value from memory into dest_reg
// the upper 24bit of the destination register can be destroyed
// this function can use FC_OP1/FC_OP2 as dest_reg which are
// not directly byte-accessible on some architectures
static void INLINE gen_mov_byte_to_reg_low_canuseword ( HostReg dest_reg , void * data ) {
gen_mov_byte_to_reg_low ( dest_reg , data ) ;
}
// move an 8bit constant value into dest_reg
// the upper 24bit of the destination register can be destroyed
// this function does not use FC_OP1/FC_OP2 as dest_reg as these
// registers might not be directly byte-accessible on some architectures
static void INLINE gen_mov_byte_to_reg_low_imm ( HostReg dest_reg , Bit8u imm ) {
gen_mov_word_to_reg_imm ( dest_reg , imm ) ;
}
// move an 8bit constant value into dest_reg
// the upper 24bit of the destination register can be destroyed
// this function can use FC_OP1/FC_OP2 as dest_reg which are
// not directly byte-accessible on some architectures
static void INLINE gen_mov_byte_to_reg_low_imm_canuseword ( HostReg dest_reg , Bit8u imm ) {
gen_mov_byte_to_reg_low_imm ( dest_reg , imm ) ;
}
// move the lowest 8bit of a register into memory
static void gen_mov_byte_from_reg_low ( HostReg src_reg , void * dest ) {
Bit16s lohalf = gen_addr_temp1 ( ( Bit32u ) dest ) ;
cache_addw ( lohalf ) ; // sb src_reg, 0(temp1)
cache_addw ( 0xA000 + ( temp1 < < 5 ) + src_reg ) ;
}
// convert an 8bit word to a 32bit dword
// the register is zero-extended (sign==false) or sign-extended (sign==true)
static void gen_extend_byte ( bool sign , HostReg reg ) {
if ( sign ) {
# if (_MIPS_ISA==MIPS32R2) || defined(PSP)
cache_addw ( ( reg < < 11 ) + 0x420 ) ; // seb reg, reg
cache_addw ( 0x7c00 + reg ) ;
# else
arch that lacks seb
# endif
} else {
cache_addw ( 0xff ) ; // andi reg, reg, 0xff
cache_addw ( 0x3000 + ( reg < < 5 ) + reg ) ;
}
}
// convert a 16bit word to a 32bit dword
// the register is zero-extended (sign==false) or sign-extended (sign==true)
static void gen_extend_word ( bool sign , HostReg reg ) {
if ( sign ) {
# if (_MIPS_ISA==MIPS32R2) || defined(PSP)
cache_addw ( ( reg < < 11 ) + 0x620 ) ; // seh reg, reg
cache_addw ( 0x7c00 + reg ) ;
# else
arch that lacks seh
# endif
} else {
cache_addw ( 0xffff ) ; // andi reg, reg, 0xffff
cache_addw ( 0x3000 + ( reg < < 5 ) + reg ) ;
}
}
// add a 32bit value from memory to a full register
static void gen_add ( HostReg reg , void * op ) {
gen_mov_word_to_reg ( temp2 , op , 1 ) ;
cache_addw ( ( reg < < 11 ) + 0x21 ) ; // addu reg, reg, temp2
cache_addw ( ( reg < < 5 ) + temp2 ) ;
}
// add a 32bit constant value to a full register
static void gen_add_imm ( HostReg reg , Bit32u imm ) {
if ( ! imm ) return ;
if ( ( ( Bit32s ) imm > = - 32768 ) & & ( ( Bit32s ) imm < 32768 ) ) {
cache_addw ( ( Bit16u ) imm ) ; // addiu reg, reg, imm
cache_addw ( 0x2400 + ( reg < < 5 ) + reg ) ;
} else {
mov_imm_to_temp1 ( imm ) ;
cache_addw ( ( reg < < 11 ) + 0x21 ) ; // addu reg, reg, temp1
cache_addw ( ( reg < < 5 ) + temp1 ) ;
}
}
// and a 32bit constant value with a full register
static void gen_and_imm ( HostReg reg , Bit32u imm ) {
if ( imm < 65536 ) {
cache_addw ( ( Bit16u ) imm ) ; // andi reg, reg, imm
cache_addw ( 0x3000 + ( reg < < 5 ) + reg ) ;
} else {
mov_imm_to_temp1 ( ( Bit32u ) imm ) ;
cache_addw ( ( reg < < 11 ) + 0x24 ) ; // and reg, temp1, reg
cache_addw ( ( temp1 < < 5 ) + reg ) ;
}
}
// move a 32bit constant value into memory
static void INLINE gen_mov_direct_dword ( void * dest , Bit32u imm ) {
gen_mov_dword_to_reg_imm ( temp2 , imm ) ;
gen_mov_word_from_reg ( temp2 , dest , 1 ) ;
}
// move an address into memory
static void INLINE gen_mov_direct_ptr ( void * dest , DRC_PTR_SIZE_IM imm ) {
gen_mov_direct_dword ( dest , ( Bit32u ) imm ) ;
}
// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
static void INLINE gen_add_direct_word ( void * dest , Bit32u imm , bool dword ) {
if ( ! imm ) return ;
gen_mov_word_to_reg ( temp2 , dest , dword ) ;
gen_add_imm ( temp2 , imm ) ;
gen_mov_word_from_reg ( temp2 , dest , dword ) ;
}
// add an 8bit constant value to a dword memory value
static void INLINE gen_add_direct_byte ( void * dest , Bit8s imm ) {
gen_add_direct_word ( dest , ( Bit32s ) imm , 1 ) ;
}
// subtract an 8bit constant value from a dword memory value
static void INLINE gen_sub_direct_byte ( void * dest , Bit8s imm ) {
gen_add_direct_word ( dest , - ( ( Bit32s ) imm ) , 1 ) ;
}
// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
static void INLINE gen_sub_direct_word ( void * dest , Bit32u imm , bool dword ) {
gen_add_direct_word ( dest , - ( Bit32s ) imm , dword ) ;
}
// effective address calculation, destination is dest_reg
// scale_reg is scaled by scale (scale_reg*(2^scale)) and
// added to dest_reg, then the immediate value is added
static INLINE void gen_lea ( HostReg dest_reg , HostReg scale_reg , Bitu scale , Bits imm ) {
if ( scale ) {
cache_addw ( ( scale_reg < < 11 ) + ( scale < < 6 ) ) ; // sll scale_reg, scale_reg, scale
cache_addw ( scale_reg ) ;
}
cache_addw ( ( dest_reg < < 11 ) + 0x21 ) ; // addu dest_reg, dest_reg, scale_reg
cache_addw ( ( dest_reg < < 5 ) + scale_reg ) ;
gen_add_imm ( dest_reg , imm ) ;
}
// effective address calculation, destination is dest_reg
// dest_reg is scaled by scale (dest_reg*(2^scale)),
// then the immediate value is added
static INLINE void gen_lea ( HostReg dest_reg , Bitu scale , Bits imm ) {
if ( scale ) {
cache_addw ( ( dest_reg < < 11 ) + ( scale < < 6 ) ) ; // sll dest_reg, dest_reg, scale
cache_addw ( dest_reg ) ;
}
gen_add_imm ( dest_reg , imm ) ;
}
# define DELAY cache_addd(0) // nop
// generate a call to a parameterless function
static void INLINE gen_call_function_raw ( void * func ) {
# if C_DEBUG
if ( ( cache . pos ^ func ) & 0xf0000000 ) LOG_MSG ( " jump overflow \n " ) ;
# endif
temp1_valid = false ;
cache_addd ( 0x0c000000 + ( ( ( Bit32u ) func > > 2 ) & 0x3ffffff ) ) ; // jal func
DELAY ;
}
// generate a call to a function with paramcount parameters
// note: the parameters are loaded in the architecture specific way
// using the gen_load_param_ functions below
static Bit32u INLINE gen_call_function_setup ( void * func , Bitu paramcount , bool fastcall = false ) {
Bit32u proc_addr = ( Bit32u ) cache . pos ;
gen_call_function_raw ( func ) ;
return proc_addr ;
}
# ifdef __mips_eabi
// max of 8 parameters in $a0-$a3 and $t0-$t3
// load an immediate value as param'th function parameter
static void INLINE gen_load_param_imm ( Bitu imm , Bitu param ) {
gen_mov_dword_to_reg_imm ( param + 4 , imm ) ;
}
// load an address as param'th function parameter
static void INLINE gen_load_param_addr ( Bitu addr , Bitu param ) {
gen_mov_dword_to_reg_imm ( param + 4 , addr ) ;
}
// load a host-register as param'th function parameter
static void INLINE gen_load_param_reg ( Bitu reg , Bitu param ) {
gen_mov_regs ( param + 4 , reg ) ;
}
// load a value from memory as param'th function parameter
static void INLINE gen_load_param_mem ( Bitu mem , Bitu param ) {
gen_mov_word_to_reg ( param + 4 , ( void * ) mem , 1 ) ;
}
# else
other mips abis
# endif
// jump to an address pointed at by ptr, offset is in imm
static void INLINE gen_jmp_ptr ( void * ptr , Bits imm = 0 ) {
gen_mov_word_to_reg ( temp2 , ptr , 1 ) ;
if ( ( imm < - 32768 ) | | ( imm > = 32768 ) ) {
gen_add_imm ( temp2 , imm ) ;
imm = 0 ;
}
temp1_valid = false ;
cache_addw ( ( Bit16u ) imm ) ; // lw temp2, imm(temp2)
cache_addw ( 0x8C00 + ( temp2 < < 5 ) + temp2 ) ;
cache_addd ( ( temp2 < < 21 ) + 8 ) ; // jr temp2
DELAY ;
}
// short conditional jump (+-127 bytes) if register is zero
// the destination is set by gen_fill_branch() later
static Bit32u INLINE gen_create_branch_on_zero ( HostReg reg , bool dword ) {
temp1_valid = false ;
if ( ! dword ) {
cache_addw ( 0xffff ) ; // andi temp1, reg, 0xffff
cache_addw ( 0x3000 + ( reg < < 5 ) + temp1 ) ;
}
cache_addw ( 0 ) ; // beq $0, reg, 0
cache_addw ( 0x1000 + ( dword ? reg : temp1 ) ) ;
DELAY ;
return ( ( Bit32u ) cache . pos - 8 ) ;
}
// short conditional jump (+-127 bytes) if register is nonzero
// the destination is set by gen_fill_branch() later
static Bit32u INLINE gen_create_branch_on_nonzero ( HostReg reg , bool dword ) {
temp1_valid = false ;
if ( ! dword ) {
cache_addw ( 0xffff ) ; // andi temp1, reg, 0xffff
cache_addw ( 0x3000 + ( reg < < 5 ) + temp1 ) ;
}
cache_addw ( 0 ) ; // bne $0, reg, 0
cache_addw ( 0x1400 + ( dword ? reg : temp1 ) ) ;
DELAY ;
return ( ( Bit32u ) cache . pos - 8 ) ;
}
// calculate relative offset and fill it into the location pointed to by data
static void INLINE gen_fill_branch ( DRC_PTR_SIZE_IM data ) {
# if C_DEBUG
Bits len = ( Bit32u ) cache . pos - data ;
if ( len < 0 ) len = - len ;
if ( len > 126 ) LOG_MSG ( " Big jump %d " , len ) ;
# endif
temp1_valid = false ; // this is a branch target
* ( Bit16u * ) data = ( ( Bit16u ) ( ( Bit32u ) cache . pos - data - 4 ) > > 2 ) ;
}
#if 0 // assume for the moment no branch will go farther then +/- 128KB
// conditional jump if register is nonzero
// for isdword==true the 32bit of the register are tested
// for isdword==false the lowest 8bit of the register are tested
static Bit32u gen_create_branch_long_nonzero ( HostReg reg , bool isdword ) {
temp1_valid = false ;
if ( ! isdword ) {
cache_addw ( 0xff ) ; // andi temp1, reg, 0xff
cache_addw ( 0x3000 + ( reg < < 5 ) + temp1 ) ;
}
cache_addw ( 3 ) ; // beq $0, reg, +12
cache_addw ( 0x1000 + ( isdword ? reg : temp1 ) ) ;
DELAY ;
cache_addd ( 0x00000000 ) ; // fill j
DELAY ;
return ( ( Bit32u ) cache . pos - 8 ) ;
}
// compare 32bit-register against zero and jump if value less/equal than zero
static Bit32u INLINE gen_create_branch_long_leqzero ( HostReg reg ) {
temp1_valid = false ;
cache_addw ( 3 ) ; // bgtz reg, +12
cache_addw ( 0x1c00 + ( reg < < 5 ) ) ;
DELAY ;
cache_addd ( 0x00000000 ) ; // fill j
DELAY ;
return ( ( Bit32u ) cache . pos - 8 ) ;
}
// calculate long relative offset and fill it into the location pointed to by data
static void INLINE gen_fill_branch_long ( Bit32u data ) {
temp1_valid = false ;
// this is an absolute branch
* ( Bit32u * ) data = 0x08000000 + ( ( ( Bit32u ) cache . pos > > 2 ) & 0x3ffffff ) ;
}
# else
// conditional jump if register is nonzero
// for isdword==true the 32bit of the register are tested
// for isdword==false the lowest 8bit of the register are tested
static Bit32u gen_create_branch_long_nonzero ( HostReg reg , bool isdword ) {
temp1_valid = false ;
if ( ! isdword ) {
cache_addw ( 0xff ) ; // andi temp1, reg, 0xff
cache_addw ( 0x3000 + ( reg < < 5 ) + temp1 ) ;
}
cache_addw ( 0 ) ; // bne $0, reg, 0
cache_addw ( 0x1400 + ( isdword ? reg : temp1 ) ) ;
DELAY ;
return ( ( Bit32u ) cache . pos - 8 ) ;
}
// compare 32bit-register against zero and jump if value less/equal than zero
static Bit32u INLINE gen_create_branch_long_leqzero ( HostReg reg ) {
temp1_valid = false ;
cache_addw ( 0 ) ; // blez reg, 0
cache_addw ( 0x1800 + ( reg < < 5 ) ) ;
DELAY ;
return ( ( Bit32u ) cache . pos - 8 ) ;
}
// calculate long relative offset and fill it into the location pointed to by data
static void INLINE gen_fill_branch_long ( Bit32u data ) {
gen_fill_branch ( data ) ;
}
# endif
static void gen_run_code ( void ) {
temp1_valid = false ;
cache_addd ( 0x27bdfff0 ) ; // addiu $sp, $sp, -16
cache_addd ( 0xafb00004 ) ; // sw $s0, 4($sp)
cache_addd ( 0x00800008 ) ; // jr $a0
cache_addd ( 0xafbf0000 ) ; // sw $ra, 0($sp)
}
// return from a function
static void gen_return_function ( void ) {
temp1_valid = false ;
cache_addd ( 0x8fbf0000 ) ; // lw $ra, 0($sp)
cache_addd ( 0x8fb00004 ) ; // lw $s0, 4($sp)
cache_addd ( 0x03e00008 ) ; // jr $ra
cache_addd ( 0x27bd0010 ) ; // addiu $sp, $sp, 16
}
# ifdef DRC_FLAGS_INVALIDATION
// called when a call to a function can be replaced by a
// call to a simpler function
static void gen_fill_function_ptr ( Bit8u * pos , void * fct_ptr , Bitu flags_type ) {
# ifdef DRC_FLAGS_INVALIDATION_DCODE
// try to avoid function calls but rather directly fill in code
switch ( flags_type ) {
case t_ADDb :
case t_ADDw :
case t_ADDd :
* ( Bit32u * ) pos = 0x00851021 ; // addu $v0, $a0, $a1
break ;
case t_ORb :
case t_ORw :
case t_ORd :
* ( Bit32u * ) pos = 0x00851025 ; // or $v0, $a0, $a1
break ;
case t_ANDb :
case t_ANDw :
case t_ANDd :
* ( Bit32u * ) pos = 0x00851024 ; // and $v0, $a0, $a1
break ;
case t_SUBb :
case t_SUBw :
case t_SUBd :
* ( Bit32u * ) pos = 0x00851023 ; // subu $v0, $a0, $a1
break ;
case t_XORb :
case t_XORw :
case t_XORd :
* ( Bit32u * ) pos = 0x00851026 ; // xor $v0, $a0, $a1
break ;
case t_CMPb :
case t_CMPw :
case t_CMPd :
case t_TESTb :
case t_TESTw :
case t_TESTd :
* ( Bit32u * ) pos = 0 ; // nop
break ;
case t_INCb :
case t_INCw :
case t_INCd :
* ( Bit32u * ) pos = 0x24820001 ; // addiu $v0, $a0, 1
break ;
case t_DECb :
case t_DECw :
case t_DECd :
* ( Bit32u * ) pos = 0x2482ffff ; // addiu $v0, $a0, -1
break ;
case t_SHLb :
case t_SHLw :
case t_SHLd :
* ( Bit32u * ) pos = 0x00a41004 ; // sllv $v0, $a0, $a1
break ;
case t_SHRb :
case t_SHRw :
case t_SHRd :
* ( Bit32u * ) pos = 0x00a41006 ; // srlv $v0, $a0, $a1
break ;
case t_SARd :
* ( Bit32u * ) pos = 0x00a41007 ; // srav $v0, $a0, $a1
break ;
# if (_MIPS_ISA==MIPS32R2) || defined(PSP)
case t_RORd :
* ( Bit32u * ) pos = 0x00a41046 ; // rotr $v0, $a0, $a1
break ;
# endif
case t_NEGb :
case t_NEGw :
case t_NEGd :
* ( Bit32u * ) pos = 0x00041023 ; // subu $v0, $0, $a0
break ;
default :
* ( Bit32u * ) pos = 0x0c000000 + ( ( ( ( Bit32u ) fct_ptr ) > > 2 ) & 0x3ffffff ) ; // jal simple_func
break ;
}
# else
* ( Bit32u * ) pos = 0x0c000000 + ( ( ( Bit32u ) fct_ptr ) > > 2 ) & 0x3ffffff ) ; // jal simple_func
# endif
}
# endif
static void cache_block_closing ( Bit8u * block_start , Bitu block_size ) {
# ifdef PSP
// writeback dcache and invalidate icache
Bit32u inval_start = ( ( Bit32u ) block_start ) & ~ 63 ;
Bit32u inval_end = ( ( ( Bit32u ) block_start ) + block_size + 64 ) & ~ 63 ;
for ( ; inval_start < inval_end ; inval_start + = 64 ) {
__builtin_allegrex_cache ( 0x1a , inval_start ) ;
__builtin_allegrex_cache ( 0x08 , inval_start ) ;
}
# endif
}
static void cache_block_before_close ( void ) { }
# ifdef DRC_USE_SEGS_ADDR
// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero)
// 16bit moves may destroy the upper 16bit of the destination register
static void gen_mov_seg16_to_reg ( HostReg dest_reg , Bitu index ) {
// stub
}
// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero)
static void gen_mov_seg32_to_reg ( HostReg dest_reg , Bitu index ) {
// stub
}
// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero)
static void gen_add_seg32_to_reg ( HostReg reg , Bitu index ) {
// stub
}
# endif
# ifdef DRC_USE_REGS_ADDR
// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero)
// 16bit moves may destroy the upper 16bit of the destination register
static void gen_mov_regval16_to_reg ( HostReg dest_reg , Bitu index ) {
// stub
}
// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero)
static void gen_mov_regval32_to_reg ( HostReg dest_reg , Bitu index ) {
// stub
}
// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
// 16bit moves may destroy the upper 16bit of the destination register
static void gen_mov_regword_to_reg ( HostReg dest_reg , Bitu index , bool dword ) {
// stub
}
// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
// the upper 24bit of the destination register can be destroyed
// this function does not use FC_OP1/FC_OP2 as dest_reg as these
// registers might not be directly byte-accessible on some architectures
static void gen_mov_regbyte_to_reg_low ( HostReg dest_reg , Bitu index ) {
// stub
}
// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
// the upper 24bit of the destination register can be destroyed
// this function can use FC_OP1/FC_OP2 as dest_reg which are
// not directly byte-accessible on some architectures
static void INLINE gen_mov_regbyte_to_reg_low_canuseword ( HostReg dest_reg , Bitu index ) {
// stub
}
// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero)
static void gen_add_regval32_to_reg ( HostReg reg , Bitu index ) {
// stub
}
// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero)
static void gen_mov_regval16_from_reg ( HostReg src_reg , Bitu index ) {
// stub
}
// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero)
static void gen_mov_regval32_from_reg ( HostReg src_reg , Bitu index ) {
// stub
}
// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
static void gen_mov_regword_from_reg ( HostReg src_reg , Bitu index , bool dword ) {
// stub
}
// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR
static void gen_mov_regbyte_from_reg_low ( HostReg src_reg , Bitu index ) {
// stub
}
# endif