Blob Blame History Raw
From 80889f640aeb2dd85cdd1f007f8d682345aa5f78 Mon Sep 17 00:00:00 2001
From: qbix79 <qbix79@ed541006-0bf7-43e9-8c4d-6fc63c346d47>
Date: Mon, 2 Nov 2015 18:09:06 +0000
Subject: [PATCH] Apply patch by gulikoza to add support for absolute 64
 addresssing.

git-svn-id: http://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3951 ed541006-0bf7-43e9-8c4d-6fc63c346d47
---
 src/cpu/core_dynrec/risc_x64.h | 147 +++++++++++++++++++++++------------------
 1 file changed, 81 insertions(+), 66 deletions(-)

diff --git a/src/cpu/core_dynrec/risc_x64.h b/src/cpu/core_dynrec/risc_x64.h
index 0f1d949..44ccf5a 100644
--- a/src/cpu/core_dynrec/risc_x64.h
+++ b/src/cpu/core_dynrec/risc_x64.h
@@ -82,45 +82,98 @@ static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
 	cache_addb(0xc0+(reg_dst<<3)+reg_src);
 }
 
+// move a 64bit constant value into a full register
+static void gen_mov_reg_qword(HostReg dest_reg,Bit64u imm) {
+	cache_addb(0x48);
+	cache_addb(0xb8+dest_reg);			// mov dest_reg,imm
+	cache_addq(imm);
+}
 
-static INLINE void gen_reg_memaddr(HostReg reg,void* data) {
-	Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+5);
+
+// This function generates an instruction with register addressing and a memory location
+static INLINE void gen_reg_memaddr(HostReg reg,void* data,Bit8u op,Bit8u prefix=0) {
+	Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+(prefix?7:6));
 //	if ((diff<0x80000000LL) && (diff>-0x80000000LL)) { //clang messes itself up on this...
 	if ( (diff>>63) == (diff>>31) ) { //signed bit extend, test to see if value fits in a Bit32s
+		// mov reg,[rip+diff] (or similar, depending on the op) to fetch *data
+		if(prefix) cache_addb(prefix);
+		cache_addb(op);
 		cache_addb(0x05+(reg<<3));
 		// RIP-relative addressing is offset after the instruction 
 		cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL)); 
 	} else if ((Bit64u)data<0x100000000LL) {
+		// mov reg,[data] (or similar, depending on the op) when absolute address of data is <4GB
+		if(prefix) cache_addb(prefix);
+		cache_addb(op);
 		cache_addw(0x2504+(reg<<3));
 		cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL));
 	} else {
-		E_Exit("DRC64:Unhandled memory reference");
+		// load 64-bit data into tmp_reg and do mov reg,[tmp_reg] (or similar, depending on the op)
+		HostReg tmp_reg = HOST_EAX;
+		if(reg == HOST_EAX) tmp_reg = HOST_ECX;
+
+		cache_addb(0x50+tmp_reg);	// push rax/rcx
+		gen_mov_reg_qword(tmp_reg,(Bit64u)data);
+
+		if(prefix) cache_addb(prefix);
+		cache_addb(op);
+		cache_addb(tmp_reg+(reg<<3));
+
+		cache_addb(0x58+tmp_reg);	// pop rax/rcx
 	}
 }
 
-static INLINE void gen_memaddr(Bitu op,void* data,Bitu off) {
-	Bit64s diff;
-	diff = (Bit64s)data-((Bit64s)cache.pos+off+5);
+// Same as above, but with immediate addressing and a memory location
+static INLINE void gen_memaddr(Bitu modreg,void* data,Bitu off,Bitu imm,Bit8u op,Bit8u prefix=0) {
+	Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+off+(prefix?7:6));
 //	if ((diff<0x80000000LL) && (diff>-0x80000000LL)) {
 	if ( (diff>>63) == (diff>>31) ) {
 		// RIP-relative addressing is offset after the instruction 
-		cache_addb(op+1);
-		cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL)); 
+		if(prefix) cache_addb(prefix);
+		cache_addw(op+((modreg+1)<<8));
+		cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL));
+
+		switch(off) {
+			case 1: cache_addb(((Bit8u)imm&0xff)); break;
+			case 2: cache_addw(((Bit16u)imm&0xffff)); break;
+			case 4: cache_addd(((Bit32u)imm&0xffffffff)); break;
+		}
+
 	} else if ((Bit64u)data<0x100000000LL) {
-		cache_addb(op);
+		if(prefix) cache_addb(prefix);
+		cache_addw(op+(modreg<<8));
 		cache_addb(0x25);
 		cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL));
+
+		switch(off) {
+			case 1: cache_addb(((Bit8u)imm&0xff)); break;
+			case 2: cache_addw(((Bit16u)imm&0xffff)); break;
+			case 4: cache_addd(((Bit32u)imm&0xffffffff)); break;
+		}
+
 	} else {
-		E_Exit("DRC64:Unhandled memory reference");
+		HostReg tmp_reg = HOST_EAX;
+
+		cache_addb(0x50+tmp_reg);	// push rax
+		gen_mov_reg_qword(tmp_reg,(Bit64u)data);
+
+		if(prefix) cache_addb(prefix);
+		cache_addw(op+((modreg-4+tmp_reg)<<8));
+
+		switch(off) {
+			case 1: cache_addb(((Bit8u)imm&0xff)); break;
+			case 2: cache_addw(((Bit16u)imm&0xffff)); break;
+			case 4: cache_addd(((Bit32u)imm&0xffffffff)); break;
+		}
+
+		cache_addb(0x58+tmp_reg);	// pop rax
 	}
 }
 
 // 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) {
-	if (!dword) cache_addb(0x66);
-	cache_addb(0x8b); // mov reg,[data]
-	gen_reg_memaddr(dest_reg,data);
+static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword,Bit8u prefix=0) {
+	gen_reg_memaddr(dest_reg,data,0x8b,(dword?prefix:0x66));	// mov reg,[data]
 } 
 
 // move a 16bit constant value into dest_reg
@@ -138,10 +191,8 @@ static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
 }
 
 // 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) {
-	if (!dword) cache_addb(0x66);
-	cache_addb(0x89);	// mov [data],reg
-	gen_reg_memaddr(src_reg,dest);
+static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword,Bit8u prefix=0) {
+	gen_reg_memaddr(src_reg,dest,0x89,(dword?prefix:0x66));		// mov [data],reg
 }
 
 // move an 8bit value from memory into dest_reg
@@ -149,8 +200,7 @@ static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) {
 // 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) {
-	cache_addb(0x8a);	// mov reg,[data]
-	gen_reg_memaddr(dest_reg,data);
+	gen_reg_memaddr(dest_reg,data,0x8a);	// mov reg, byte [data]
 }
 
 // move an 8bit value from memory into dest_reg
@@ -158,9 +208,7 @@ static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
 // this function can use FC_OP1/FC_OP2 as dest_reg which are
 // not directly byte-accessible on some architectures
 static void gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
-	cache_addb(0x66);
-	cache_addb(0x8b);	// mov reg,[data]
-	gen_reg_memaddr(dest_reg,data);
+	gen_reg_memaddr(dest_reg,data,0x8b,0x66);	// mov reg, word [data]
 }
 
 // move an 8bit constant value into dest_reg
@@ -184,8 +232,7 @@ static void gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
 
 // move the lowest 8bit of a register into memory
 static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
-	cache_addb(0x88);	// mov [data],reg
-	gen_reg_memaddr(src_reg,dest);
+	gen_reg_memaddr(src_reg,dest,0x88);	// mov byte [data],reg
 }
 
 
@@ -208,8 +255,7 @@ static void gen_extend_word(bool sign,HostReg reg) {
 
 // add a 32bit value from memory to a full register
 static void gen_add(HostReg reg,void* op) {
-	cache_addb(0x03);					// add reg,[data]
-	gen_reg_memaddr(reg,op);
+	gen_reg_memaddr(reg,op,0x03);		// add reg,[data]
 }
 
 // add a 32bit constant value to a full register
@@ -228,31 +274,20 @@ static void gen_and_imm(HostReg reg,Bit32u imm) {
 
 // move a 32bit constant value into memory
 static void gen_mov_direct_dword(void* dest,Bit32u imm) {
-	cache_addb(0xc7);					// mov [data],imm
-	gen_memaddr(0x04,dest,4);
-	cache_addd(imm);
+	gen_memaddr(0x4,dest,4,imm,0xc7);	// mov [data],imm
 }
 
-// move a 64bit constant value into a full register
-static void gen_mov_reg_qword(HostReg dest_reg,Bit64u imm) {
-	cache_addb(0x48);
-	cache_addb(0xb8+dest_reg);			// mov dest_reg,imm
-	cache_addq(imm);
-}
 
 // move an address into memory
 static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
 	gen_mov_reg_qword(HOST_EAX,imm);
-	cache_addb(0x48);
-	gen_mov_word_from_reg(HOST_EAX,dest,true);
+	gen_mov_word_from_reg(HOST_EAX,dest,true,0x48);		// 0x48 prefixes full 64-bit mov
 }
 
 
 // add an 8bit constant value to a memory value
 static void gen_add_direct_byte(void* dest,Bit8s imm) {
-	cache_addb(0x83);					// add [data],imm
-	gen_memaddr(0x4,dest,1);
-	cache_addb(imm);
+	gen_memaddr(0x4,dest,1,imm,0x83);	// add [data],imm
 }
 
 // add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
@@ -261,22 +296,12 @@ static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
 		gen_add_direct_byte(dest,(Bit8s)imm);
 		return;
 	}
-	if (!dword) cache_addb(0x66);
-	cache_addb(0x81);					// add [data],imm
-	if (dword) {
-		gen_memaddr(0x4,dest,4);		// size of following immediate value
-		cache_addd((Bit32u)imm);
-	} else {
-		gen_memaddr(0x4,dest,2);		// size of following immediate value
-		cache_addw((Bit16u)imm);
-	}
+	gen_memaddr(0x4,dest,(dword?4:2),imm,0x81,(dword?0:0x66));	// add [data],imm
 }
 
 // subtract an 8bit constant value from a memory value
 static void gen_sub_direct_byte(void* dest,Bit8s imm) {
-	cache_addb(0x83);					// sub [data],imm
-	gen_memaddr(0x2c,dest,1);
-	cache_addb(imm);
+	gen_memaddr(0x2c,dest,1,imm,0x83);
 }
 
 // subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
@@ -285,15 +310,7 @@ static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
 		gen_sub_direct_byte(dest,(Bit8s)imm);
 		return;
 	}
-	if (!dword) cache_addb(0x66);
-	cache_addw(0x81);					// sub [data],imm
-	if (dword) {
-		gen_memaddr(0x2c,dest,4);		// size of following immediate value
-		cache_addd((Bit32u)imm);
-	} else {
-		gen_memaddr(0x2c,dest,2);		// size of following immediate value
-		cache_addw((Bit16u)imm);
-	}
+	gen_memaddr(0x2c,dest,(dword?4:2),imm,0x81,(dword?0:0x66));	// sub [data],imm
 }
 
 
@@ -510,12 +527,10 @@ static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
 			break;
 #if defined (_MSC_VER)
 		case 2:		// mov r8,[mem]
-			cache_addb(0x49);
-			gen_mov_word_to_reg(0,(void*)mem,true);
+			gen_mov_word_to_reg(0,(void*)mem,true,0x49);	// 0x49, use x64 rX regs
 			break;
 		case 3:		// mov r9,[mem]
-			cache_addb(0x49);
-			gen_mov_word_to_reg(1,(void*)mem,true);
+			gen_mov_word_to_reg(1,(void*)mem,true,0x49);	// 0x49, use x64 rX regs
 			break;
 #else
 		case 2:		// mov rdx,[mem]
-- 
2.7.0