summaryrefslogtreecommitdiff
path: root/src/arch/x86/isa/microops
diff options
context:
space:
mode:
authorAndreas Sandberg <andreas@sandberg.pp.se>2013-09-30 12:00:20 +0200
committerAndreas Sandberg <andreas@sandberg.pp.se>2013-09-30 12:00:20 +0200
commit654d1e675a3dc1f598aeadb0824bdb3357820a59 (patch)
treee249108fcd6737dda985b993c95d926a33abca21 /src/arch/x86/isa/microops
parentc299dcedc6d73aab56d9c659623d7112c2e9c4bb (diff)
downloadgem5-654d1e675a3dc1f598aeadb0824bdb3357820a59.tar.xz
x86: Add support for loading 32-bit and 80-bit floats in the x87
The x87 FPU supports three floating point formats: 32-bit, 64-bit, and 80-bit floats. The current gem5 implementation supports 32-bit and 64-bit floats, but only works correctly for 64-bit floats. This changeset fixes the 32-bit float handling by correctly loading and rounding (using truncation) 32-bit floats instead of simply truncating the bit pattern. 80-bit floats are loaded by first loading the 80-bits of the float to two temporary integer registers. A micro-op (cvtint_fp80) then converts the contents of the two integer registers to the internal FP representation (double). Similarly, when storing an 80-bit float, there are two conversion routines (ctvfp80h_int and cvtfp80l_int) that convert an internal FP register to 80-bit and stores the upper 64-bits or lower 32-bits to an integer register, which is the written to memory using normal integer stores.
Diffstat (limited to 'src/arch/x86/isa/microops')
-rw-r--r--src/arch/x86/isa/microops/fpop.isa33
-rw-r--r--src/arch/x86/isa/microops/ldstop.isa36
2 files changed, 65 insertions, 4 deletions
diff --git a/src/arch/x86/isa/microops/fpop.isa b/src/arch/x86/isa/microops/fpop.isa
index 8a77914d9..3c6753712 100644
--- a/src/arch/x86/isa/microops/fpop.isa
+++ b/src/arch/x86/isa/microops/fpop.isa
@@ -295,9 +295,10 @@ let {{
class ConvOp(FpBinaryOp):
abstract = True
op_class = 'FloatCvtOp'
- def __init__(self, dest, src1):
+ def __init__(self, dest, src1, **kwargs):
super(ConvOp, self).__init__(dest, src1, \
- "InstRegIndex(FLOATREG_MICROFP0)")
+ "InstRegIndex(FLOATREG_MICROFP0)", \
+ **kwargs)
# These probably shouldn't look at the ExtMachInst directly to figure
# out what size to use and should instead delegate that to the macroop's
@@ -324,6 +325,34 @@ let {{
SDestReg = merge(SDestReg, intSrcReg1, 4);
'''
+ # Convert two integers registers representing an 80-bit floating
+ # point number to an x87 register.
+ class cvtint_fp80(FpBinaryOp):
+ code = '''
+ uint8_t bits[10];
+ *(uint64_t *)(bits + 0) = SSrcReg1;
+ *(uint16_t *)(bits + 8) = (uint16_t)SSrcReg2;
+ FpDestReg = loadFloat80(bits);
+ '''
+
+ # Convert an x87 register (double) into extended precision and
+ # extract the highest 64 bits.
+ class cvtfp80h_int(ConvOp):
+ code = '''
+ char bits[10];
+ storeFloat80(bits, FpSrcReg1);
+ SDestReg = *(uint64_t *)(bits + 0);
+ '''
+
+ # Convert an x87 register (double) into extended precision and
+ # extract the lowest 16 bits.
+ class cvtfp80l_int(ConvOp):
+ code = '''
+ char bits[10];
+ storeFloat80(bits, FpSrcReg1);
+ SDestReg = *(uint16_t *)(bits + 8);
+ '''
+
# These need to consider size at some point. They'll always use doubles
# for the moment.
class addfp(FpBinaryOp):
diff --git a/src/arch/x86/isa/microops/ldstop.isa b/src/arch/x86/isa/microops/ldstop.isa
index 75519f417..1b22b88de 100644
--- a/src/arch/x86/isa/microops/ldstop.isa
+++ b/src/arch/x86/isa/microops/ldstop.isa
@@ -410,7 +410,22 @@ let {{
defineMicroLoadOp('Ldstl', 'Data = merge(Data, Mem, dataSize);',
'Data = Mem & mask(dataSize * 8);',
'(StoreCheck << FlagShift) | Request::LOCKED')
- defineMicroLoadOp('Ldfp', 'FpData_uqw = Mem;', big = False)
+
+ defineMicroLoadOp('Ldfp', code='FpData_uqw = Mem', big = False)
+
+ defineMicroLoadOp('Ldfp87', code='''
+ switch (dataSize)
+ {
+ case 4:
+ FpData_df = *(float *)&Mem;
+ break;
+ case 8:
+ FpData_df = *(double *)&Mem;
+ break;
+ default:
+ panic("Unhandled data size in LdFp87.\\n");
+ }
+ ''', big = False)
def defineMicroStoreOp(mnemonic, code, completeCode="", mem_flags="0"):
global header_output
@@ -447,7 +462,24 @@ let {{
defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);')
defineMicroStoreOp('Stul', 'Mem = pick(Data, 2, dataSize);',
mem_flags="Request::LOCKED")
- defineMicroStoreOp('Stfp', 'Mem = FpData_uqw;')
+
+ defineMicroStoreOp('Stfp', code='Mem = FpData_uqw;')
+
+ defineMicroStoreOp('Stfp87', code='''
+ switch (dataSize)
+ {
+ case 4: {
+ float single(FpData_df);
+ Mem = *(uint32_t *)&single;
+ } break;
+ case 8:
+ Mem = *(uint64_t *)&FpData_df;
+ break;
+ default:
+ panic("Unhandled data size in StFp87.\\n");
+ }
+ ''')
+
defineMicroStoreOp('Cda', 'Mem = 0;', mem_flags="Request::NO_ACCESS")
iop = InstObjParams("lea", "Lea", 'X86ISA::LdStOp',