dmult & dmultu emulation
PATCH 1/1 dmult & dmultu emulation
Hi,
The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.
On x86_64, it uses the mul/imul instruction, an equivalent C code (but much slower) is provided for other architectures.
Cheers,
Aurelien
Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v retrieving revision 1.45
op_helper.c +39 -6
@@ -230,16 +230,49 @@ void do_div (void)#ifdef TARGET_MIPS64 void do_dmult (void ) { - env->LO = (int64_t )T0 * (int64_t )T1 ; -/* XXX */ - env->HI = (env->LO | (1ULL <<63 )) ? ~0ULL :0ULL ; +#if defined(__x86_64__) + __asm__ ("imul %0\n\t" + :"=d" (env->HI),"=a" (env->LO) + :"a" (T0 ),"0" (T1 ) + ); +#else +int64_t ph; +uint64_t pm1, pm2, pl; + + pl = (uint64_t )((uint32_t )T0 ) * (uint64_t )((uint32_t )T1 ); + pm1 = ((int64_t )T0 >>32 ) * (uint32_t )T1 ; + pm2 = (uint32_t )T0 * ((int64_t )T1 >>32 ); + ph = ((int64_t )T0 >>32 ) * ((int64_t )T1 >>32 ); + + ph += ((int64_t )pm1) >>32 ; + pm1 = (uint64_t )((uint32_t )pm1) + pm2 + (pl >>32 ); + + env->HI = ph + ((int64_t )pm1) >>32 ; + env->LO = (pm1 <<32 ) + (uint32_t )pl; +#endif }void do_dmultu (void ) { - env->LO =T0 *T1 ; -/* XXX */ - env->HI =0 ; +#if defined(__x86_64__) + __asm__ ("mul %0\n\t" + :"=d" (env->HI),"=a" (env->LO) + :"a" (T0 ),"0" (T1 ) + ); +#else +uint64_t ph, pm1, pm2, pl; + + pl = (uint64_t )((uint32_t )T0 ) * (uint64_t )((uint32_t )T1 ); + pm1 = (T0 >>32 ) * (uint32_t )T1 ; + pm2 = (uint32_t )T0 * (T1 >>32 ); + ph = (T0 >>32 ) * (T1 >>32 ); + + ph += pm1 >>32 ; + pm1 = (uint64_t )((uint32_t )pm1) + pm2 + (pl >>32 ); + + env->HI = ph + (pm1 >>32 ); + env->LO = (pm1 <<32 ) + (uint32_t )pl; +#endif }void do_ddiv (void )
Signature · 4 lines
.''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [email protected] | [email protected] `- people.debian.org/~aurel32 | www.aurel32.net
Quoted 2 lines
The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.
Can we share the implementation between targets please. We already have an implementation of mul64 in target-i386/helper.c.
I've no real preference which implementation we use, I just don't want there to be several of them.
Paul
Quoted 8 lines · Paul Brook
Quoted 2 lines
The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.
Can we share the implementation between targets please. We already have an implementation of mul64 in
target-i386/helper.c.I've no real preference which implementation we use, I just don't want there to be several of them.
Ok, please find an updated patch below. The multiplications functions are in mul64.c and are now shared by the i386 and mips targets.
Bye,
Aurelien
Index: Makefile.target
===================================================================
RCS file: /sources/qemu/qemu/Makefile.target,v
retrieving revision 1.169
Makefile.target +1 -0
@@ -365,6 +365,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.o VL_OBJS+=cutils.o +VL_OBJS+=mul64.o VL_OBJS+=block.o block-raw.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o VL_OBJS+=irq.o
Index: exec-all.h
===================================================================
RCS file: /sources/qemu/qemu/exec-all.h,v
retrieving revision 1.54
exec-all.h +3 -0
@@ -78,6 +78,9 @@ void optimize_flags_init(void);extern FILE *logfile;extern int loglevel; +void muls64 (int64_t *phigh,int64_t *plow,int64_t a,int64_t b); +void mulu64 (uint64_t *phigh,uint64_t *plow,uint64_t a,uint64_t b); +int gen_intermediate_code (CPUState *env,struct TranslationBlock *tb);int gen_intermediate_code_pc (CPUState *env,struct TranslationBlock *tb);void dump_ops (const uint16_t *opc_buf,const uint32_t *opparam_buf);
Index: target-i386/helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper.c,v retrieving revision 1.80
helper.c +3 -47
74 lines not on this page · raw message
Index: target-mips/exec.h
===================================================================
RCS file: /sources/qemu/qemu/target-mips/exec.h,v
retrieving revision 1.26
exec.h +0 -2
@@ -97,8 +97,6 @@ void do_ddiv (void);#if TARGET_LONG_BITS >HOST_LONG_BITS void do_ddivu (void );#endif -void do_dmult (void ); -void do_dmultu (void );#endif void do_mfc0_random (void );void do_mfc0_count (void );
Index: target-mips/op.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op.c,v
retrieving revision 1.54
op.c +2 -2
@@ -874,13 +874,13 @@ void op_msubu (void)#ifdef TARGET_MIPS64 void op_dmult (void ) { -CALL_FROM_TB0 (do_dmult); +CALL_FROM_TB4 (muls64, &(env->HI), &(env->LO),T0 ,T1 );RETURN (); }void op_dmultu (void ) { -CALL_FROM_TB0 (do_dmultu); +CALL_FROM_TB4 (mulu64, &(env->HI), &(env->LO),T0 ,T1 );RETURN (); }#endif
Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v retrieving revision 1.45
op_helper.c +0 -14
@@ -228,20 +228,6 @@ void do_div (void)#endif #ifdef TARGET_MIPS64 -void do_dmult (void ) -{ - env->LO = (int64_t )T0 * (int64_t )T1 ; -/* XXX */ - env->HI = (env->LO | (1ULL <<63 )) ? ~0ULL :0ULL ; -} - -void do_dmultu (void ) -{ - env->LO =T0 *T1 ; -/* XXX */ - env->HI =0 ; -} -void do_ddiv (void ) {if (T1 !=0 ) {
mul64.c +77 -0
77 lines not on this page · raw message
Signature · 4 lines
.''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [email protected] | [email protected] `- people.debian.org/~aurel32 | www.aurel32.net
Would this patch work with other 64-bit processors, or is it x86-64-only? I'm mainly thinking about 64-bit PowerPCs, but I don't know if PowerPCs uses the same method.
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 3 lines · C.W. Betts
Would this patch work with other 64-bit processors, or is it x86-64-only? I'm mainly thinking about 64-bit PowerPCs, but I don't know if PowerPCs uses the same method.
You may have missed the x86-64 specific assembly code in there.
Thiemo
Quoted 3 lines · C.W. Betts
Would this patch work with other 64-bit processors, or is it x86-64-only? I'm mainly thinking about 64-bit PowerPCs, but I don't know if PowerPCs uses the same method.
This patch works on all hosts CPU using the C version, but it can use an assembly version for x86_64. If there is the equivalent assembly instruction for 64-bit PowerPCs, it is possible to add it to this file.
Signature · 4 lines
.''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [email protected] | [email protected] `- people.debian.org/~aurel32 | www.aurel32.net
Quoted 4 lines · Aurelien Jarno
Quoted 3 lines · Paul Brook
Quoted 2 lines
The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.
Quoted 9 lines
Quoted 5 lines
Can we share the implementation between targets please. We already have an implementation of mul64 in
target-i386/helper.c.I've no real preference which implementation we use, I just don't want there to be several of them.
Ok, please find an updated patch below. The multiplications functions are in
mul64.cand are now shared by the i386 and mips targets.
03:40 < pbrook> aurel32: I think you've got a sign mismatch in your target-i386/helper.c patch. You've replaced imul64 with mulu64.
I confirm I have made a mistake here, please find an updated patch below.
Bye,
Aurelien
Index: Makefile.target
===================================================================
RCS file: /sources/qemu/qemu/Makefile.target,v
retrieving revision 1.169
Makefile.target +1 -0
@@ -365,6 +365,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.o VL_OBJS+=cutils.o +VL_OBJS+=mul64.o VL_OBJS+=block.o block-raw.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o VL_OBJS+=irq.o
Index: exec-all.h
===================================================================
RCS file: /sources/qemu/qemu/exec-all.h,v
retrieving revision 1.54
exec-all.h +3 -0
@@ -78,6 +78,9 @@ void optimize_flags_init(void);extern FILE *logfile;extern int loglevel; +void muls64 (int64_t *phigh,int64_t *plow,int64_t a,int64_t b); +void mulu64 (uint64_t *phigh,uint64_t *plow,uint64_t a,uint64_t b); +int gen_intermediate_code (CPUState *env,struct TranslationBlock *tb);int gen_intermediate_code_pc (CPUState *env,struct TranslationBlock *tb);void dump_ops (const uint16_t *opc_buf,const uint32_t *opparam_buf);
Index: target-i386/helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper.c,v retrieving revision 1.80
helper.c +3 -47
74 lines not on this page · raw message
Index: target-mips/exec.h
===================================================================
RCS file: /sources/qemu/qemu/target-mips/exec.h,v
retrieving revision 1.26
exec.h +0 -2
@@ -97,8 +97,6 @@ void do_ddiv (void);#if TARGET_LONG_BITS >HOST_LONG_BITS void do_ddivu (void );#endif -void do_dmult (void ); -void do_dmultu (void );#endif void do_mfc0_random (void );void do_mfc0_count (void );
Index: target-mips/op.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op.c,v
retrieving revision 1.54
op.c +2 -2
@@ -874,13 +874,13 @@ void op_msubu (void)#ifdef TARGET_MIPS64 void op_dmult (void ) { -CALL_FROM_TB0 (do_dmult); +CALL_FROM_TB4 (muls64, &(env->HI), &(env->LO),T0 ,T1 );RETURN (); }void op_dmultu (void ) { -CALL_FROM_TB0 (do_dmultu); +CALL_FROM_TB4 (mulu64, &(env->HI), &(env->LO),T0 ,T1 );RETURN (); }#endif
Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v retrieving revision 1.45
op_helper.c +0 -14
@@ -228,20 +228,6 @@ void do_div (void)#endif #ifdef TARGET_MIPS64 -void do_dmult (void ) -{ - env->LO = (int64_t )T0 * (int64_t )T1 ; -/* XXX */ - env->HI = (env->LO | (1ULL <<63 )) ? ~0ULL :0ULL ; -} - -void do_dmultu (void ) -{ - env->LO =T0 *T1 ; -/* XXX */ - env->HI =0 ; -} -void do_ddiv (void ) {if (T1 !=0 ) {
mul64.c +78 -0
78 lines not on this page · raw message
Signature · 4 lines
.''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [email protected] | [email protected] `- people.debian.org/~aurel32 | www.aurel32.net
Quoted 11 lines · Aurelien Jarno
Quoted 10 lines · Aurelien Jarno
Quoted 8 lines · Paul Brook
Quoted 2 lines
The patch below fixes the emulation of dmult and dmultu by doing a real 64x64 -> 128 multiplication.
Can we share the implementation between targets please. We already have an implementation of mul64 in
target-i386/helper.c.I've no real preference which implementation we use, I just don't want there to be several of them.
Quoted 8 lines
Quoted 3 lines
Ok, please find an updated patch below. The multiplications functions are in
mul64.cand are now shared by the i386 and mips targets.03:40 < pbrook> aurel32: I think you've got a sign mismatch in your
target-i386/helper.cpatch. You've replaced imul64 with mulu64.I confirm I have made a mistake here, please find an updated patch below.
I moved the file to host-utils.c, there may be more such functions needed some day.
Thiemo