diff options
author | Andreas Sandberg <andreas@sandberg.pp.se> | 2013-09-30 12:00:20 +0200 |
---|---|---|
committer | Andreas Sandberg <andreas@sandberg.pp.se> | 2013-09-30 12:00:20 +0200 |
commit | 654d1e675a3dc1f598aeadb0824bdb3357820a59 (patch) | |
tree | e249108fcd6737dda985b993c95d926a33abca21 /src/arch/x86/isa/microops | |
parent | c299dcedc6d73aab56d9c659623d7112c2e9c4bb (diff) | |
download | gem5-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.isa | 33 | ||||
-rw-r--r-- | src/arch/x86/isa/microops/ldstop.isa | 36 |
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', |