Merge zizzer:/z/m5/Bitkeeper/m5
[gem5.git] / cpu / base_cpu.cc
1 /*
2 * Copyright (c) 2002-2004 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <iostream>
30 #include <string>
31 #include <sstream>
32
33 #include "base/cprintf.hh"
34 #include "base/loader/symtab.hh"
35 #include "base/misc.hh"
36 #include "base/output.hh"
37 #include "cpu/base_cpu.hh"
38 #include "cpu/exec_context.hh"
39 #include "cpu/sampling_cpu/sampling_cpu.hh"
40 #include "sim/param.hh"
41 #include "sim/sim_events.hh"
42
43 using namespace std;
44
45 vector<BaseCPU *> BaseCPU::cpuList;
46
47 // This variable reflects the max number of threads in any CPU. Be
48 // careful to only use it once all the CPUs that you care about have
49 // been initialized
50 int maxThreadsPerCPU = 1;
51
52 #ifdef FULL_SYSTEM
53 BaseCPU::BaseCPU(Params *p)
54 : SimObject(p->name), frequency(p->freq), checkInterrupts(true),
55 params(p), number_of_threads(p->numberOfThreads), system(p->system)
56 #else
57 BaseCPU::BaseCPU(Params *p)
58 : SimObject(p->name), params(p), number_of_threads(p->numberOfThreads)
59 #endif
60 {
61 // add self to global list of CPUs
62 cpuList.push_back(this);
63
64 if (number_of_threads > maxThreadsPerCPU)
65 maxThreadsPerCPU = number_of_threads;
66
67 // allocate per-thread instruction-based event queues
68 comInstEventQueue = new EventQueue *[number_of_threads];
69 for (int i = 0; i < number_of_threads; ++i)
70 comInstEventQueue[i] = new EventQueue("instruction-based event queue");
71
72 //
73 // set up instruction-count-based termination events, if any
74 //
75 if (p->max_insts_any_thread != 0)
76 for (int i = 0; i < number_of_threads; ++i)
77 new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
78 "a thread reached the max instruction count");
79
80 if (p->max_insts_all_threads != 0) {
81 // allocate & initialize shared downcounter: each event will
82 // decrement this when triggered; simulation will terminate
83 // when counter reaches 0
84 int *counter = new int;
85 *counter = number_of_threads;
86 for (int i = 0; i < number_of_threads; ++i)
87 new CountedExitEvent(comInstEventQueue[i],
88 "all threads reached the max instruction count",
89 p->max_insts_all_threads, *counter);
90 }
91
92 // allocate per-thread load-based event queues
93 comLoadEventQueue = new EventQueue *[number_of_threads];
94 for (int i = 0; i < number_of_threads; ++i)
95 comLoadEventQueue[i] = new EventQueue("load-based event queue");
96
97 //
98 // set up instruction-count-based termination events, if any
99 //
100 if (p->max_loads_any_thread != 0)
101 for (int i = 0; i < number_of_threads; ++i)
102 new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
103 "a thread reached the max load count");
104
105 if (p->max_loads_all_threads != 0) {
106 // allocate & initialize shared downcounter: each event will
107 // decrement this when triggered; simulation will terminate
108 // when counter reaches 0
109 int *counter = new int;
110 *counter = number_of_threads;
111 for (int i = 0; i < number_of_threads; ++i)
112 new CountedExitEvent(comLoadEventQueue[i],
113 "all threads reached the max load count",
114 p->max_loads_all_threads, *counter);
115 }
116
117 #ifdef FULL_SYSTEM
118 memset(interrupts, 0, sizeof(interrupts));
119 intstatus = 0;
120 #endif
121
122 functionTracingEnabled = false;
123 if (p->functionTrace) {
124 functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
125 currentFunctionStart = currentFunctionEnd = 0;
126 functionEntryTick = p->functionTraceStart;
127
128 if (p->functionTraceStart == 0) {
129 functionTracingEnabled = true;
130 } else {
131 Event *e =
132 new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,
133 true);
134 e->schedule(p->functionTraceStart);
135 }
136 }
137 }
138
139
140 void
141 BaseCPU::enableFunctionTrace()
142 {
143 functionTracingEnabled = true;
144 }
145
146 BaseCPU::~BaseCPU()
147 {
148 }
149
150 void
151 BaseCPU::init()
152 {
153 if (!params->deferRegistration)
154 registerExecContexts();
155 }
156
157 void
158 BaseCPU::regStats()
159 {
160 using namespace Stats;
161
162 numCycles
163 .name(name() + ".numCycles")
164 .desc("number of cpu cycles simulated")
165 ;
166
167 int size = execContexts.size();
168 if (size > 1) {
169 for (int i = 0; i < size; ++i) {
170 stringstream namestr;
171 ccprintf(namestr, "%s.ctx%d", name(), i);
172 execContexts[i]->regStats(namestr.str());
173 }
174 } else if (size == 1)
175 execContexts[0]->regStats(name());
176 }
177
178
179 void
180 BaseCPU::registerExecContexts()
181 {
182 for (int i = 0; i < execContexts.size(); ++i) {
183 ExecContext *xc = execContexts[i];
184 int cpu_id;
185
186 #ifdef FULL_SYSTEM
187 cpu_id = system->registerExecContext(xc);
188 #else
189 cpu_id = xc->process->registerExecContext(xc);
190 #endif
191
192 xc->cpu_id = cpu_id;
193 }
194 }
195
196
197 void
198 BaseCPU::switchOut(SamplingCPU *sampler)
199 {
200 // default: do nothing, signal done
201 sampler->signalSwitched();
202 }
203
204 void
205 BaseCPU::takeOverFrom(BaseCPU *oldCPU)
206 {
207 assert(execContexts.size() == oldCPU->execContexts.size());
208
209 for (int i = 0; i < execContexts.size(); ++i) {
210 ExecContext *newXC = execContexts[i];
211 ExecContext *oldXC = oldCPU->execContexts[i];
212
213 newXC->takeOverFrom(oldXC);
214 assert(newXC->cpu_id == oldXC->cpu_id);
215 #ifdef FULL_SYSTEM
216 system->replaceExecContext(newXC, newXC->cpu_id);
217 #else
218 assert(newXC->process == oldXC->process);
219 newXC->process->replaceExecContext(newXC, newXC->cpu_id);
220 #endif
221 }
222
223 #ifdef FULL_SYSTEM
224 for (int i = 0; i < NumInterruptLevels; ++i)
225 interrupts[i] = oldCPU->interrupts[i];
226 intstatus = oldCPU->intstatus;
227 #endif
228 }
229
230
231 #ifdef FULL_SYSTEM
232 void
233 BaseCPU::post_interrupt(int int_num, int index)
234 {
235 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
236
237 if (int_num < 0 || int_num >= NumInterruptLevels)
238 panic("int_num out of bounds\n");
239
240 if (index < 0 || index >= sizeof(uint64_t) * 8)
241 panic("int_num out of bounds\n");
242
243 checkInterrupts = true;
244 interrupts[int_num] |= 1 << index;
245 intstatus |= (ULL(1) << int_num);
246 }
247
248 void
249 BaseCPU::clear_interrupt(int int_num, int index)
250 {
251 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
252
253 if (int_num < 0 || int_num >= NumInterruptLevels)
254 panic("int_num out of bounds\n");
255
256 if (index < 0 || index >= sizeof(uint64_t) * 8)
257 panic("int_num out of bounds\n");
258
259 interrupts[int_num] &= ~(1 << index);
260 if (interrupts[int_num] == 0)
261 intstatus &= ~(ULL(1) << int_num);
262 }
263
264 void
265 BaseCPU::clear_interrupts()
266 {
267 DPRINTF(Interrupt, "Interrupts all cleared\n");
268
269 memset(interrupts, 0, sizeof(interrupts));
270 intstatus = 0;
271 }
272
273
274 void
275 BaseCPU::serialize(std::ostream &os)
276 {
277 SERIALIZE_ARRAY(interrupts, NumInterruptLevels);
278 SERIALIZE_SCALAR(intstatus);
279 }
280
281 void
282 BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
283 {
284 UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels);
285 UNSERIALIZE_SCALAR(intstatus);
286 }
287
288 #endif // FULL_SYSTEM
289
290 void
291 BaseCPU::traceFunctionsInternal(Addr pc)
292 {
293 if (!debugSymbolTable)
294 return;
295
296 // if pc enters different function, print new function symbol and
297 // update saved range. Otherwise do nothing.
298 if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
299 string sym_str;
300 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
301 currentFunctionStart,
302 currentFunctionEnd);
303
304 if (!found) {
305 // no symbol found: use addr as label
306 sym_str = csprintf("0x%x", pc);
307 currentFunctionStart = pc;
308 currentFunctionEnd = pc + 1;
309 }
310
311 ccprintf(*functionTraceStream, " (%d)\n%d: %s",
312 curTick - functionEntryTick, curTick, sym_str);
313 functionEntryTick = curTick;
314 }
315 }
316
317
318 DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)