mem-cache: Add multiple eviction stats
[gem5.git] / src / arch / x86 / utility.cc
1 /*
2 * Copyright (c) 2007 The Hewlett-Packard Development Company
3 * Copyright (c) 2011 Advanced Micro Devices, Inc.
4 * All rights reserved.
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions are
17 * met: redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer;
19 * redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution;
22 * neither the name of the copyright holders nor the names of its
23 * contributors may be used to endorse or promote products derived from
24 * this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 * Authors: Gabe Black
39 */
40
41 #include "arch/x86/utility.hh"
42
43 #include "arch/x86/interrupts.hh"
44 #include "arch/x86/registers.hh"
45 #include "arch/x86/x86_traits.hh"
46 #include "cpu/base.hh"
47 #include "fputils/fp80.h"
48 #include "sim/full_system.hh"
49
50 namespace X86ISA {
51
52 uint64_t
53 getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp)
54 {
55 if (fp) {
56 panic("getArgument(): Floating point arguments not implemented\n");
57 } else if (size != 8) {
58 panic("getArgument(): Can only handle 64-bit arguments.\n");
59 }
60
61 // The first 6 integer arguments are passed in registers, the rest
62 // are passed on the stack.
63 const int int_reg_map[] = {
64 INTREG_RDI, INTREG_RSI, INTREG_RDX,
65 INTREG_RCX, INTREG_R8, INTREG_R9
66 };
67 if (number < sizeof(int_reg_map) / sizeof(*int_reg_map)) {
68 return tc->readIntReg(int_reg_map[number]);
69 } else {
70 panic("getArgument(): Don't know how to handle stack arguments.\n");
71 }
72 }
73
74 void
75 initCPU(ThreadContext *tc, int cpuId)
76 {
77 InitInterrupt(0).invoke(tc);
78 }
79
80 void startupCPU(ThreadContext *tc, int cpuId)
81 {
82 if (cpuId == 0 || !FullSystem) {
83 tc->activate();
84 } else {
85 // This is an application processor (AP). It should be initialized to
86 // look like only the BIOS POST has run on it and put then put it into
87 // a halted state.
88 tc->suspend();
89 }
90 }
91
92 void
93 copyMiscRegs(ThreadContext *src, ThreadContext *dest)
94 {
95 // This function assumes no side effects other than TLB invalidation
96 // need to be considered while copying state. That will likely not be
97 // true in the future.
98 for (int i = 0; i < NUM_MISCREGS; ++i) {
99 if (!isValidMiscReg(i))
100 continue;
101
102 dest->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i));
103 }
104
105 // The TSC has to be updated with side-effects if the CPUs in a
106 // CPU switch have different frequencies.
107 dest->setMiscReg(MISCREG_TSC, src->readMiscReg(MISCREG_TSC));
108
109 dest->getITBPtr()->flushAll();
110 dest->getDTBPtr()->flushAll();
111 }
112
113 void
114 copyRegs(ThreadContext *src, ThreadContext *dest)
115 {
116 //copy int regs
117 for (int i = 0; i < NumIntRegs; ++i)
118 dest->setIntRegFlat(i, src->readIntRegFlat(i));
119 //copy float regs
120 for (int i = 0; i < NumFloatRegs; ++i)
121 dest->setFloatRegFlat(i, src->readFloatRegFlat(i));
122 //copy condition-code regs
123 for (int i = 0; i < NumCCRegs; ++i)
124 dest->setCCRegFlat(i, src->readCCRegFlat(i));
125 copyMiscRegs(src, dest);
126 dest->pcState(src->pcState());
127 }
128
129 void
130 skipFunction(ThreadContext *tc)
131 {
132 panic("Not implemented for x86\n");
133 }
134
135 uint64_t
136 getRFlags(ThreadContext *tc)
137 {
138 const uint64_t ncc_flags(tc->readMiscRegNoEffect(MISCREG_RFLAGS));
139 const uint64_t cc_flags(tc->readCCReg(X86ISA::CCREG_ZAPS));
140 const uint64_t cfof_bits(tc->readCCReg(X86ISA::CCREG_CFOF));
141 const uint64_t df_bit(tc->readCCReg(X86ISA::CCREG_DF));
142 // ecf (PSEUDO(3)) & ezf (PSEUDO(4)) are only visible to
143 // microcode, so we can safely ignore them.
144
145 // Reconstruct the real rflags state, mask out internal flags, and
146 // make sure reserved bits have the expected values.
147 return ((ncc_flags | cc_flags | cfof_bits | df_bit) & 0x3F7FD5)
148 | 0x2;
149 }
150
151 void
152 setRFlags(ThreadContext *tc, uint64_t val)
153 {
154 tc->setCCReg(X86ISA::CCREG_ZAPS, val & ccFlagMask);
155 tc->setCCReg(X86ISA::CCREG_CFOF, val & cfofMask);
156 tc->setCCReg(X86ISA::CCREG_DF, val & DFBit);
157
158 // Internal microcode registers (ECF & EZF)
159 tc->setCCReg(X86ISA::CCREG_ECF, 0);
160 tc->setCCReg(X86ISA::CCREG_EZF, 0);
161
162 // Update the RFLAGS misc reg with whatever didn't go into the
163 // magic registers.
164 tc->setMiscReg(MISCREG_RFLAGS, val & ~(ccFlagMask | cfofMask | DFBit));
165 }
166
167 uint8_t
168 convX87TagsToXTags(uint16_t ftw)
169 {
170 uint8_t ftwx(0);
171 for (int i = 0; i < 8; ++i) {
172 // Extract the tag for the current element on the FP stack
173 const unsigned tag((ftw >> (2 * i)) & 0x3);
174
175 /*
176 * Check the type of the current FP element. Valid values are:
177 * 0 == Valid
178 * 1 == Zero
179 * 2 == Special (Nan, unsupported, infinity, denormal)
180 * 3 == Empty
181 */
182 // The xsave version of the tag word only keeps track of
183 // whether the element is empty or not. Set the corresponding
184 // bit in the ftwx if it's not empty,
185 if (tag != 0x3)
186 ftwx |= 1 << i;
187 }
188
189 return ftwx;
190 }
191
192 uint16_t
193 convX87XTagsToTags(uint8_t ftwx)
194 {
195 uint16_t ftw(0);
196 for (int i = 0; i < 8; ++i) {
197 const unsigned xtag(((ftwx >> i) & 0x1));
198
199 // The xtag for an x87 stack position is 0 for empty stack positions.
200 if (!xtag) {
201 // Set the tag word to 3 (empty) for the current element.
202 ftw |= 0x3 << (2 * i);
203 } else {
204 // TODO: We currently assume that non-empty elements are
205 // valid (0x0), but we should ideally reconstruct the full
206 // state (valid/zero/special).
207 }
208 }
209
210 return ftw;
211 }
212
213 uint16_t
214 genX87Tags(uint16_t ftw, uint8_t top, int8_t spm)
215 {
216 const uint8_t new_top((top + spm + 8) % 8);
217
218 if (spm > 0) {
219 // Removing elements from the stack. Flag the elements as empty.
220 for (int i = top; i != new_top; i = (i + 1 + 8) % 8)
221 ftw |= 0x3 << (2 * i);
222 } else if (spm < 0) {
223 // Adding elements to the stack. Flag the new elements as
224 // valid. We should ideally decode them and "do the right
225 // thing".
226 for (int i = new_top; i != top; i = (i + 1 + 8) % 8)
227 ftw &= ~(0x3 << (2 * i));
228 }
229
230 return ftw;
231 }
232
233 double
234 loadFloat80(const void *_mem)
235 {
236 fp80_t fp80;
237 memcpy(fp80.bits, _mem, 10);
238
239 return fp80_cvtd(fp80);
240 }
241
242 void
243 storeFloat80(void *_mem, double value)
244 {
245 fp80_t fp80 = fp80_cvfd(value);
246 memcpy(_mem, fp80.bits, 10);
247 }
248
249 } // namespace X86_ISA