utility.cc revision 10058
12810Srdreslin@umich.edu/*
212500Snikos.nikoleris@arm.com * Copyright (c) 2007 The Hewlett-Packard Development Company
311051Sandreas.hansson@arm.com * Copyright (c) 2011 Advanced Micro Devices, Inc.
411051Sandreas.hansson@arm.com * All rights reserved.
511051Sandreas.hansson@arm.com *
611051Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
711051Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
811051Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
911051Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
1011051Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
1111051Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
1211051Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
1311051Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
1411051Sandreas.hansson@arm.com *
1511051Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
162810Srdreslin@umich.edu * modification, are permitted provided that the following conditions are
172810Srdreslin@umich.edu * met: redistributions of source code must retain the above copyright
182810Srdreslin@umich.edu * notice, this list of conditions and the following disclaimer;
192810Srdreslin@umich.edu * redistributions in binary form must reproduce the above copyright
202810Srdreslin@umich.edu * notice, this list of conditions and the following disclaimer in the
212810Srdreslin@umich.edu * documentation and/or other materials provided with the distribution;
222810Srdreslin@umich.edu * neither the name of the copyright holders nor the names of its
232810Srdreslin@umich.edu * contributors may be used to endorse or promote products derived from
242810Srdreslin@umich.edu * this software without specific prior written permission.
252810Srdreslin@umich.edu *
262810Srdreslin@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
272810Srdreslin@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
282810Srdreslin@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
292810Srdreslin@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
302810Srdreslin@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
312810Srdreslin@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
322810Srdreslin@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
332810Srdreslin@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
342810Srdreslin@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
352810Srdreslin@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
362810Srdreslin@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
372810Srdreslin@umich.edu *
382810Srdreslin@umich.edu * Authors: Gabe Black
392810Srdreslin@umich.edu */
402810Srdreslin@umich.edu
412810Srdreslin@umich.edu#include "arch/x86/interrupts.hh"
4211051Sandreas.hansson@arm.com#include "arch/x86/registers.hh"
4311051Sandreas.hansson@arm.com#include "arch/x86/tlb.hh"
442810Srdreslin@umich.edu#include "arch/x86/utility.hh"
4511051Sandreas.hansson@arm.com#include "arch/x86/x86_traits.hh"
4611051Sandreas.hansson@arm.com#include "cpu/base.hh"
4712349Snikos.nikoleris@arm.com#include "fputils/fp80.h"
482810Srdreslin@umich.edu#include "sim/system.hh"
492810Srdreslin@umich.edu
502810Srdreslin@umich.edunamespace X86ISA {
512810Srdreslin@umich.edu
5211051Sandreas.hansson@arm.comuint64_t
532810Srdreslin@umich.edugetArgument(ThreadContext *tc, int &number, uint16_t size, bool fp)
542810Srdreslin@umich.edu{
5511051Sandreas.hansson@arm.com    if (!FullSystem) {
562810Srdreslin@umich.edu        panic("getArgument() only implemented for full system mode.\n");
5712334Sgabeblack@google.com    } else if (fp) {
5811051Sandreas.hansson@arm.com        panic("getArgument(): Floating point arguments not implemented\n");
5911051Sandreas.hansson@arm.com    } else if (size != 8) {
6011051Sandreas.hansson@arm.com        panic("getArgument(): Can only handle 64-bit arguments.\n");
6111051Sandreas.hansson@arm.com    }
6211288Ssteve.reinhardt@amd.com
6311051Sandreas.hansson@arm.com    // The first 6 integer arguments are passed in registers, the rest
6411051Sandreas.hansson@arm.com    // are passed on the stack.
6511051Sandreas.hansson@arm.com    const int int_reg_map[] = {
6611051Sandreas.hansson@arm.com        INTREG_RDI, INTREG_RSI, INTREG_RDX,
6711051Sandreas.hansson@arm.com        INTREG_RCX, INTREG_R8, INTREG_R9
6811053Sandreas.hansson@arm.com    };
6911053Sandreas.hansson@arm.com    if (number < sizeof(int_reg_map) / sizeof(*int_reg_map)) {
7011051Sandreas.hansson@arm.com        return tc->readIntReg(int_reg_map[number]);
7111051Sandreas.hansson@arm.com    } else {
7211051Sandreas.hansson@arm.com        panic("getArgument(): Don't know how to handle stack arguments.\n");
7311197Sandreas.hansson@arm.com    }
7411197Sandreas.hansson@arm.com}
7511199Sandreas.hansson@arm.com
7611197Sandreas.hansson@arm.comvoid initCPU(ThreadContext *tc, int cpuId)
7712084Sspwilson2@wisc.edu{
7812084Sspwilson2@wisc.edu    // This function is essentially performing a reset. The actual INIT
7911197Sandreas.hansson@arm.com    // interrupt does a subset of this, so we'll piggyback on some of its
8011051Sandreas.hansson@arm.com    // functionality.
8111051Sandreas.hansson@arm.com    InitInterrupt init(0);
8211051Sandreas.hansson@arm.com    init.invoke(tc);
8311051Sandreas.hansson@arm.com
8411051Sandreas.hansson@arm.com    PCState pc = tc->pcState();
8511051Sandreas.hansson@arm.com    pc.upc(0);
8611051Sandreas.hansson@arm.com    pc.nupc(1);
8711051Sandreas.hansson@arm.com    tc->pcState(pc);
8811051Sandreas.hansson@arm.com
8911051Sandreas.hansson@arm.com    // These next two loops zero internal microcode and implicit registers.
9011051Sandreas.hansson@arm.com    // They aren't specified by the ISA but are used internally by M5's
9111051Sandreas.hansson@arm.com    // implementation.
9211051Sandreas.hansson@arm.com    for (int index = 0; index < NumMicroIntRegs; index++) {
9311051Sandreas.hansson@arm.com        tc->setIntReg(INTREG_MICRO(index), 0);
9411051Sandreas.hansson@arm.com    }
9511051Sandreas.hansson@arm.com
9611051Sandreas.hansson@arm.com    for (int index = 0; index < NumImplicitIntRegs; index++) {
9711051Sandreas.hansson@arm.com        tc->setIntReg(INTREG_IMPLICIT(index), 0);
9811051Sandreas.hansson@arm.com    }
9911051Sandreas.hansson@arm.com
10011051Sandreas.hansson@arm.com    // Set integer register EAX to 0 to indicate that the optional BIST
10111051Sandreas.hansson@arm.com    // passed. No BIST actually runs, but software may still check this
10211051Sandreas.hansson@arm.com    // register for errors.
10311051Sandreas.hansson@arm.com    tc->setIntReg(INTREG_RAX, 0);
10411051Sandreas.hansson@arm.com
10511051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_CR0, 0x0000000060000010ULL);
10611051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_CR8, 0);
10711051Sandreas.hansson@arm.com
10811051Sandreas.hansson@arm.com    // TODO initialize x87, 64 bit, and 128 bit media state
10911051Sandreas.hansson@arm.com
11011051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRRCAP, 0x0508);
11111051Sandreas.hansson@arm.com    for (int i = 0; i < 8; i++) {
11211051Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_MTRR_PHYS_BASE(i), 0);
11311051Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_MTRR_PHYS_MASK(i), 0);
11411051Sandreas.hansson@arm.com    }
11511051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_64K_00000, 0);
11611051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_16K_80000, 0);
11711051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_16K_A0000, 0);
11811051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_4K_C0000, 0);
11911051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_4K_C8000, 0);
12011051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_4K_D0000, 0);
12111051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_4K_D8000, 0);
12211051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_4K_E0000, 0);
12311051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_4K_E8000, 0);
12411051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_4K_F0000, 0);
12511051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MTRR_FIX_4K_F8000, 0);
12611051Sandreas.hansson@arm.com
12711051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_DEF_TYPE, 0);
12811051Sandreas.hansson@arm.com
12911051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MCG_CAP, 0x104);
13011051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MCG_STATUS, 0);
13111051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_MCG_CTL, 0);
13211051Sandreas.hansson@arm.com
13311051Sandreas.hansson@arm.com    for (int i = 0; i < 5; i++) {
13411051Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_MC_CTL(i), 0);
13511051Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_MC_STATUS(i), 0);
13611051Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_MC_ADDR(i), 0);
13711051Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_MC_MISC(i), 0);
13811051Sandreas.hansson@arm.com    }
13911051Sandreas.hansson@arm.com
14011051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_TSC, 0);
14111051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_TSC_AUX, 0);
14211051Sandreas.hansson@arm.com
14311051Sandreas.hansson@arm.com    for (int i = 0; i < 4; i++) {
14411051Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_PERF_EVT_SEL(i), 0);
14511051Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_PERF_EVT_CTR(i), 0);
14611051Sandreas.hansson@arm.com    }
14711051Sandreas.hansson@arm.com
14811051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_STAR, 0);
14911051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_LSTAR, 0);
15011051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_CSTAR, 0);
15111601Sandreas.hansson@arm.com
15211601Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_SF_MASK, 0);
15311051Sandreas.hansson@arm.com
15411051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_KERNEL_GS_BASE, 0);
15511051Sandreas.hansson@arm.com
15611051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_SYSENTER_CS, 0);
15711051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_SYSENTER_ESP, 0);
15811051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_SYSENTER_EIP, 0);
15911051Sandreas.hansson@arm.com
16011051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_PAT, 0x0007040600070406ULL);
16111051Sandreas.hansson@arm.com
16211051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_SYSCFG, 0x20601);
16311284Sandreas.hansson@arm.com
16411051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_IORR_BASE0, 0);
16511051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_IORR_BASE1, 0);
16611051Sandreas.hansson@arm.com
16711051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_IORR_MASK0, 0);
16811051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_IORR_MASK1, 0);
16911051Sandreas.hansson@arm.com
17011051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_TOP_MEM, 0x4000000);
17111284Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_TOP_MEM2, 0x0);
17211284Sandreas.hansson@arm.com
17311284Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_DEBUG_CTL_MSR, 0);
17411284Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_LAST_BRANCH_FROM_IP, 0);
17511051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_LAST_BRANCH_TO_IP, 0);
17611284Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_LAST_EXCEPTION_FROM_IP, 0);
17711051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_LAST_EXCEPTION_TO_IP, 0);
17811051Sandreas.hansson@arm.com
17911051Sandreas.hansson@arm.com    // Invalidate the caches (this should already be done for us)
18011284Sandreas.hansson@arm.com
18111284Sandreas.hansson@arm.com    LocalApicBase lApicBase = 0;
18211284Sandreas.hansson@arm.com    lApicBase.base = 0xFEE00000 >> 12;
18311284Sandreas.hansson@arm.com    lApicBase.enable = 1;
18411051Sandreas.hansson@arm.com    lApicBase.bsp = (cpuId == 0);
18511744Snikos.nikoleris@arm.com    tc->setMiscReg(MISCREG_APIC_BASE, lApicBase);
18611051Sandreas.hansson@arm.com
18711051Sandreas.hansson@arm.com    Interrupts * interrupts = dynamic_cast<Interrupts *>(
18811051Sandreas.hansson@arm.com            tc->getCpuPtr()->getInterruptController());
18911051Sandreas.hansson@arm.com    assert(interrupts);
19011286Sandreas.hansson@arm.com
19111286Sandreas.hansson@arm.com    interrupts->setRegNoEffect(APIC_ID, cpuId << 24);
19211286Sandreas.hansson@arm.com
19311051Sandreas.hansson@arm.com    interrupts->setRegNoEffect(APIC_VERSION, (5 << 16) | 0x14);
19411286Sandreas.hansson@arm.com
19511600Sandreas.hansson@arm.com    // TODO Set the SMRAM base address (SMBASE) to 0x00030000
19611600Sandreas.hansson@arm.com
19711051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_VM_CR, 0);
19811051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_IGNNE, 0);
19911051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_SMM_CTL, 0);
20011284Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_VM_HSAVE_PA, 0);
20111051Sandreas.hansson@arm.com}
20211051Sandreas.hansson@arm.com
20311051Sandreas.hansson@arm.comvoid startupCPU(ThreadContext *tc, int cpuId)
20411602Sandreas.hansson@arm.com{
20511051Sandreas.hansson@arm.com    if (cpuId == 0 || !FullSystem) {
20611051Sandreas.hansson@arm.com        tc->activate(Cycles(0));
20711284Sandreas.hansson@arm.com    } else {
20811051Sandreas.hansson@arm.com        // This is an application processor (AP). It should be initialized to
20911284Sandreas.hansson@arm.com        // look like only the BIOS POST has run on it and put then put it into
21011602Sandreas.hansson@arm.com        // a halted state.
21111051Sandreas.hansson@arm.com        tc->suspend(Cycles(0));
21211051Sandreas.hansson@arm.com    }
21311284Sandreas.hansson@arm.com}
21411051Sandreas.hansson@arm.com
21511284Sandreas.hansson@arm.comvoid
21611284Sandreas.hansson@arm.comcopyMiscRegs(ThreadContext *src, ThreadContext *dest)
21711284Sandreas.hansson@arm.com{
21811051Sandreas.hansson@arm.com    // This function assumes no side effects other than TLB invalidation
21911051Sandreas.hansson@arm.com    // need to be considered while copying state. That will likely not be
22011051Sandreas.hansson@arm.com    // true in the future.
22111284Sandreas.hansson@arm.com    for (int i = 0; i < NUM_MISCREGS; ++i) {
22211284Sandreas.hansson@arm.com        if ( ( i != MISCREG_CR1 &&
22311284Sandreas.hansson@arm.com             !(i > MISCREG_CR4 && i < MISCREG_CR8) &&
22411284Sandreas.hansson@arm.com             !(i > MISCREG_CR8 && i <= MISCREG_CR15) ) == false) {
22511051Sandreas.hansson@arm.com             continue;
22611051Sandreas.hansson@arm.com        }
22711051Sandreas.hansson@arm.com        dest->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i));
22811284Sandreas.hansson@arm.com    }
22911284Sandreas.hansson@arm.com
23011284Sandreas.hansson@arm.com    // The TSC has to be updated with side-effects if the CPUs in a
23111197Sandreas.hansson@arm.com    // CPU switch have different frequencies.
23211601Sandreas.hansson@arm.com    dest->setMiscReg(MISCREG_TSC, src->readMiscReg(MISCREG_TSC));
23311601Sandreas.hansson@arm.com
23411601Sandreas.hansson@arm.com    dest->getITBPtr()->flushAll();
23511601Sandreas.hansson@arm.com    dest->getDTBPtr()->flushAll();
23611601Sandreas.hansson@arm.com}
23711601Sandreas.hansson@arm.com
23811601Sandreas.hansson@arm.comvoid
23911601Sandreas.hansson@arm.comcopyRegs(ThreadContext *src, ThreadContext *dest)
24011197Sandreas.hansson@arm.com{
24111601Sandreas.hansson@arm.com    //copy int regs
24211601Sandreas.hansson@arm.com    for (int i = 0; i < NumIntRegs; ++i)
24311601Sandreas.hansson@arm.com         dest->setIntRegFlat(i, src->readIntRegFlat(i));
24411601Sandreas.hansson@arm.com    //copy float regs
24511601Sandreas.hansson@arm.com    for (int i = 0; i < NumFloatRegs; ++i)
24611601Sandreas.hansson@arm.com         dest->setFloatRegBitsFlat(i, src->readFloatRegBitsFlat(i));
24711601Sandreas.hansson@arm.com    //copy condition-code regs
24811051Sandreas.hansson@arm.com    for (int i = 0; i < NumCCRegs; ++i)
24911051Sandreas.hansson@arm.com         dest->setCCRegFlat(i, src->readCCRegFlat(i));
25011051Sandreas.hansson@arm.com    copyMiscRegs(src, dest);
25111051Sandreas.hansson@arm.com    dest->pcState(src->pcState());
25211051Sandreas.hansson@arm.com}
25311284Sandreas.hansson@arm.com
25411284Sandreas.hansson@arm.comvoid
25511051Sandreas.hansson@arm.comskipFunction(ThreadContext *tc)
25611051Sandreas.hansson@arm.com{
25711051Sandreas.hansson@arm.com    panic("Not implemented for x86\n");
25811051Sandreas.hansson@arm.com}
25911284Sandreas.hansson@arm.com
26011051Sandreas.hansson@arm.comuint64_t
26111051Sandreas.hansson@arm.comgetRFlags(ThreadContext *tc)
26211602Sandreas.hansson@arm.com{
26311602Sandreas.hansson@arm.com    const uint64_t ncc_flags(tc->readMiscRegNoEffect(MISCREG_RFLAGS));
26411602Sandreas.hansson@arm.com    const uint64_t cc_flags(tc->readCCReg(X86ISA::CCREG_ZAPS));
26511602Sandreas.hansson@arm.com    const uint64_t cfof_bits(tc->readCCReg(X86ISA::CCREG_CFOF));
26611602Sandreas.hansson@arm.com    const uint64_t df_bit(tc->readCCReg(X86ISA::CCREG_DF));
26711602Sandreas.hansson@arm.com    // ecf (PSEUDO(3)) & ezf (PSEUDO(4)) are only visible to
26811602Sandreas.hansson@arm.com    // microcode, so we can safely ignore them.
26911602Sandreas.hansson@arm.com
27011602Sandreas.hansson@arm.com    // Reconstruct the real rflags state, mask out internal flags, and
27111602Sandreas.hansson@arm.com    // make sure reserved bits have the expected values.
27211602Sandreas.hansson@arm.com    return ((ncc_flags | cc_flags | cfof_bits | df_bit) & 0x3F7FD5)
27311051Sandreas.hansson@arm.com        | 0x2;
27411602Sandreas.hansson@arm.com}
27511197Sandreas.hansson@arm.com
27611744Snikos.nikoleris@arm.comvoid
27711744Snikos.nikoleris@arm.comsetRFlags(ThreadContext *tc, uint64_t val)
27811051Sandreas.hansson@arm.com{
27911051Sandreas.hansson@arm.com    tc->setCCReg(X86ISA::CCREG_ZAPS, val & ccFlagMask);
28011051Sandreas.hansson@arm.com    tc->setCCReg(X86ISA::CCREG_CFOF, val & cfofMask);
28111051Sandreas.hansson@arm.com    tc->setCCReg(X86ISA::CCREG_DF, val & DFBit);
28211051Sandreas.hansson@arm.com
28311051Sandreas.hansson@arm.com    // Internal microcode registers (ECF & EZF)
28411051Sandreas.hansson@arm.com    tc->setCCReg(X86ISA::CCREG_ECF, 0);
28511051Sandreas.hansson@arm.com    tc->setCCReg(X86ISA::CCREG_EZF, 0);
28611051Sandreas.hansson@arm.com
28711051Sandreas.hansson@arm.com    // Update the RFLAGS misc reg with whatever didn't go into the
28811051Sandreas.hansson@arm.com    // magic registers.
28911051Sandreas.hansson@arm.com    tc->setMiscReg(MISCREG_RFLAGS, val & ~(ccFlagMask | cfofMask | DFBit));
29011051Sandreas.hansson@arm.com}
29111051Sandreas.hansson@arm.com
29211051Sandreas.hansson@arm.comuint8_t
29311051Sandreas.hansson@arm.comconvX87TagsToXTags(uint16_t ftw)
29411051Sandreas.hansson@arm.com{
29511051Sandreas.hansson@arm.com    uint8_t ftwx(0);
29611051Sandreas.hansson@arm.com    for (int i = 0; i < 8; ++i) {
29711051Sandreas.hansson@arm.com        // Extract the tag for the current element on the FP stack
29811744Snikos.nikoleris@arm.com        const unsigned tag((ftw >> (2 * i)) & 0x3);
29911051Sandreas.hansson@arm.com
30011051Sandreas.hansson@arm.com        /*
30111744Snikos.nikoleris@arm.com         * Check the type of the current FP element. Valid values are:
30211051Sandreas.hansson@arm.com         * 0 == Valid
30311051Sandreas.hansson@arm.com         * 1 == Zero
30411051Sandreas.hansson@arm.com         * 2 == Special (Nan, unsupported, infinity, denormal)
30511051Sandreas.hansson@arm.com         * 3 == Empty
30611199Sandreas.hansson@arm.com         */
30711051Sandreas.hansson@arm.com        // The xsave version of the tag word only keeps track of
30811051Sandreas.hansson@arm.com        // whether the element is empty or not. Set the corresponding
30911051Sandreas.hansson@arm.com        // bit in the ftwx if it's not empty,
31011867Snikos.nikoleris@arm.com        if (tag != 0x3)
31111051Sandreas.hansson@arm.com            ftwx |= 1 << i;
31211051Sandreas.hansson@arm.com    }
31311484Snikos.nikoleris@arm.com
31411051Sandreas.hansson@arm.com    return ftwx;
31511051Sandreas.hansson@arm.com}
31611051Sandreas.hansson@arm.com
31711051Sandreas.hansson@arm.comuint16_t
31811051Sandreas.hansson@arm.comconvX87XTagsToTags(uint8_t ftwx)
31911051Sandreas.hansson@arm.com{
32011051Sandreas.hansson@arm.com    uint16_t ftw(0);
32111870Snikos.nikoleris@arm.com    for (int i = 0; i < 8; ++i) {
32211051Sandreas.hansson@arm.com        const unsigned xtag(((ftwx >> i) & 0x1));
32311744Snikos.nikoleris@arm.com
32411051Sandreas.hansson@arm.com        // The xtag for an x87 stack position is 0 for empty stack positions.
32511051Sandreas.hansson@arm.com        if (!xtag) {
32612349Snikos.nikoleris@arm.com            // Set the tag word to 3 (empty) for the current element.
32712349Snikos.nikoleris@arm.com            ftw |= 0x3 << (2 * i);
32812349Snikos.nikoleris@arm.com        } else {
32912349Snikos.nikoleris@arm.com            // TODO: We currently assume that non-empty elements are
33012349Snikos.nikoleris@arm.com            // valid (0x0), but we should ideally reconstruct the full
33112349Snikos.nikoleris@arm.com            // state (valid/zero/special).
33212349Snikos.nikoleris@arm.com        }
33312349Snikos.nikoleris@arm.com    }
33412349Snikos.nikoleris@arm.com
33511051Sandreas.hansson@arm.com    return ftw;
33611199Sandreas.hansson@arm.com}
33711051Sandreas.hansson@arm.com
33811051Sandreas.hansson@arm.comuint16_t
33911051Sandreas.hansson@arm.comgenX87Tags(uint16_t ftw, uint8_t top, int8_t spm)
34011051Sandreas.hansson@arm.com{
34111051Sandreas.hansson@arm.com    const uint8_t new_top((top + spm + 8) % 8);
34211051Sandreas.hansson@arm.com
34311051Sandreas.hansson@arm.com    if (spm > 0) {
34411051Sandreas.hansson@arm.com        // Removing elements from the stack. Flag the elements as empty.
34511375Sandreas.hansson@arm.com        for (int i = top; i != new_top; i = (i + 1 + 8) % 8)
34611375Sandreas.hansson@arm.com            ftw |= 0x3 << (2 * i);
34711375Sandreas.hansson@arm.com    } else if (spm < 0) {
34811199Sandreas.hansson@arm.com        // Adding elements to the stack. Flag the new elements as
34911199Sandreas.hansson@arm.com        // valid. We should ideally decode them and "do the right
35011199Sandreas.hansson@arm.com        // thing".
35111199Sandreas.hansson@arm.com        for (int i = new_top; i != top; i = (i + 1 + 8) % 8)
35211199Sandreas.hansson@arm.com            ftw &= ~(0x3 << (2 * i));
35311199Sandreas.hansson@arm.com    }
35411199Sandreas.hansson@arm.com
35511199Sandreas.hansson@arm.com    return ftw;
35611199Sandreas.hansson@arm.com}
35711199Sandreas.hansson@arm.com
35811199Sandreas.hansson@arm.comdouble
35911199Sandreas.hansson@arm.comloadFloat80(const void *_mem)
36011199Sandreas.hansson@arm.com{
36111199Sandreas.hansson@arm.com    const fp80_t *fp80((const fp80_t *)_mem);
36211199Sandreas.hansson@arm.com
36311199Sandreas.hansson@arm.com    return fp80_cvtd(*fp80);
36411199Sandreas.hansson@arm.com}
36511199Sandreas.hansson@arm.com
36611199Sandreas.hansson@arm.comvoid
36711199Sandreas.hansson@arm.comstoreFloat80(void *_mem, double value)
36811375Sandreas.hansson@arm.com{
36911199Sandreas.hansson@arm.com    fp80_t *fp80((fp80_t *)_mem);
37011199Sandreas.hansson@arm.com
37111051Sandreas.hansson@arm.com    *fp80 = fp80_cvfd(value);
37211051Sandreas.hansson@arm.com}
37311051Sandreas.hansson@arm.com
37411051Sandreas.hansson@arm.com} // namespace X86_ISA
37511051Sandreas.hansson@arm.com