|Subject:||Re: [Qemu-trivial] [PATCH] Fix QEMU PPC e500v1 efscmp* instructions|
|Date:||Wed, 18 May 2016 08:04:21 +0000|
With more information at hand with the reference manual from Freescale
http://cache.nxp.com/files/32bit/doc/ref_manual/SPEPEM.pdf , I was able to
revisit my patch and figure out what is actually going on.
Before applying any patch, efscmp* instructions in QEMU set crD values as
(0b0100 << 2) = 0b10000 (consider the HELPER_SINGLE_SPE_CMP macro which left
shifts the value returned by efscmp* instruction by 2 bits). A value of 0b10000
is not correct according the to the reference manual.
The reference manual expects efscmp* instructions to return a value of 0b0100.
Please find attached an updated patch qemu-patch-5 which disables left shifting in
HELPER_SINGLE_SPE_CMP macro. This macro is used by efscmp* and efstst*
instructions only. efstst* instruction handlers call efscmp* handlers.
Traditionally, each crD (condition register nibble) consist of 4 bits, which is
set by comparisons as follows:
crD = W X Y Z
W = Less than
X = Greater than
Y = Equal to
However, efscmp* instructions being a special case return a binary result.
(efscmpeq will set the crD = 0bx1xx iff when op1 == op2 and 0bx0xx otherwise;
i.e. there is no notion of different crD values based on Less than, Greater
than and Equal to).
This effectively means that crD will store a "Greater than" comparison result
iff efscmp* instruction comparison is TRUE. Compiler exploits this feature by
checking for "Branch if Less than or Equal to" (ble instruction) OR "Branch if
Greater than" (bgt instruction) for Branch if FALSE OR Branch if TRUE
respectively after an efscmp* instruction. This can be seen in a assembly code
27 if (__real__ x != 3.0f || __imag__ x != 4.0f)
10000498: lwz r10,8(r31)
1000049c: lis r9,16448
100004a0: efscmpeq cr7,r10,r9
100004a4: ble- cr7,0x100004b8 <bar+60> //jump to abort() call
100004a8: lwz r10,12(r31)
100004ac: lis r9,16512
100004b0: efscmpeq cr7,r10,r9
100004b4: bgt- cr7,0x100004bc <bar+64> //skip abort() call
28 abort ();
100004b8: bl 0x10000808 <abort>
Comments and suggestions are welcome.
|[Prev in Thread]||Current Thread||[Next in Thread]|