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 <string>
30 #include <sstream>
31 #include <iostream>
32
33 #include "cpu/base_cpu.hh"
34 #include "base/cprintf.hh"
35 #include "cpu/exec_context.hh"
36 #include "base/misc.hh"
37 #include "sim/param.hh"
38 #include "sim/sim_events.hh"
39
40 using namespace std;
41
42 vector<BaseCPU *> BaseCPU::cpuList;
43
44 // This variable reflects the max number of threads in any CPU. Be
45 // careful to only use it once all the CPUs that you care about have
46 // been initialized
47 int maxThreadsPerCPU = 1;
48
49 #ifdef FULL_SYSTEM
50 BaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg,
51 Counter max_insts_any_thread,
52 Counter max_insts_all_threads,
53 Counter max_loads_any_thread,
54 Counter max_loads_all_threads,
55 System *_system, Tick freq)
56 : SimObject(_name), frequency(freq), checkInterrupts(true),
57 deferRegistration(_def_reg), number_of_threads(_number_of_threads),
58 system(_system)
59 #else
60 BaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg,
61 Counter max_insts_any_thread,
62 Counter max_insts_all_threads,
63 Counter max_loads_any_thread,
64 Counter max_loads_all_threads)
65 : SimObject(_name), deferRegistration(_def_reg),
66 number_of_threads(_number_of_threads)
67 #endif
68 {
69 // add self to global list of CPUs
70 cpuList.push_back(this);
71
72 if (number_of_threads > maxThreadsPerCPU)
73 maxThreadsPerCPU = number_of_threads;
74
75 // allocate per-thread instruction-based event queues
76 comInstEventQueue = new (EventQueue *)[number_of_threads];
77 for (int i = 0; i < number_of_threads; ++i)
78 comInstEventQueue[i] = new EventQueue("instruction-based event queue");
79
80 //
81 // set up instruction-count-based termination events, if any
82 //
83 if (max_insts_any_thread != 0)
84 for (int i = 0; i < number_of_threads; ++i)
85 new SimExitEvent(comInstEventQueue[i], max_insts_any_thread,
86 "a thread reached the max instruction count");
87
88 if (max_insts_all_threads != 0) {
89 // allocate & initialize shared downcounter: each event will
90 // decrement this when triggered; simulation will terminate
91 // when counter reaches 0
92 int *counter = new int;
93 *counter = number_of_threads;
94 for (int i = 0; i < number_of_threads; ++i)
95 new CountedExitEvent(comInstEventQueue[i],
96 "all threads reached the max instruction count",
97 max_insts_all_threads, *counter);
98 }
99
100 // allocate per-thread load-based event queues
101 comLoadEventQueue = new (EventQueue *)[number_of_threads];
102 for (int i = 0; i < number_of_threads; ++i)
103 comLoadEventQueue[i] = new EventQueue("load-based event queue");
104
105 //
106 // set up instruction-count-based termination events, if any
107 //
108 if (max_loads_any_thread != 0)
109 for (int i = 0; i < number_of_threads; ++i)
110 new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread,
111 "a thread reached the max load count");
112
113 if (max_loads_all_threads != 0) {
114 // allocate & initialize shared downcounter: each event will
115 // decrement this when triggered; simulation will terminate
116 // when counter reaches 0
117 int *counter = new int;
118 *counter = number_of_threads;
119 for (int i = 0; i < number_of_threads; ++i)
120 new CountedExitEvent(comLoadEventQueue[i],
121 "all threads reached the max load count",
122 max_loads_all_threads, *counter);
123 }
124
125 #ifdef FULL_SYSTEM
126 memset(interrupts, 0, sizeof(interrupts));
127 intstatus = 0;
128 #endif
129 }
130
131 void
132 BaseCPU::init()
133 {
134 if (!deferRegistration)
135 registerExecContexts();
136 }
137
138 void
139 BaseCPU::regStats()
140 {
141 using namespace Stats;
142
143 numCycles
144 .name(name() + ".numCycles")
145 .desc("number of cpu cycles simulated")
146 ;
147
148 int size = execContexts.size();
149 if (size > 1) {
150 for (int i = 0; i < size; ++i) {
151 stringstream namestr;
152 ccprintf(namestr, "%s.ctx%d", name(), i);
153 execContexts[i]->regStats(namestr.str());
154 }
155 } else if (size == 1)
156 execContexts[0]->regStats(name());
157 }
158
159
160 void
161 BaseCPU::registerExecContexts()
162 {
163 for (int i = 0; i < execContexts.size(); ++i) {
164 ExecContext *xc = execContexts[i];
165 int cpu_id;
166
167 #ifdef FULL_SYSTEM
168 cpu_id = system->registerExecContext(xc);
169 #else
170 cpu_id = xc->process->registerExecContext(xc);
171 #endif
172
173 xc->cpu_id = cpu_id;
174 }
175 }
176
177
178 void
179 BaseCPU::switchOut()
180 {
181 // default: do nothing
182 }
183
184 void
185 BaseCPU::takeOverFrom(BaseCPU *oldCPU)
186 {
187 assert(execContexts.size() == oldCPU->execContexts.size());
188
189 for (int i = 0; i < execContexts.size(); ++i) {
190 ExecContext *newXC = execContexts[i];
191 ExecContext *oldXC = oldCPU->execContexts[i];
192
193 newXC->takeOverFrom(oldXC);
194 assert(newXC->cpu_id == oldXC->cpu_id);
195 #ifdef FULL_SYSTEM
196 system->replaceExecContext(newXC, newXC->cpu_id);
197 #else
198 assert(newXC->process == oldXC->process);
199 newXC->process->replaceExecContext(newXC, newXC->cpu_id);
200 #endif
201 }
202
203 #ifdef FULL_SYSTEM
204 for (int i = 0; i < NumInterruptLevels; ++i)
205 interrupts[i] = oldCPU->interrupts[i];
206 intstatus = oldCPU->intstatus;
207 #endif
208 }
209
210
211 #ifdef FULL_SYSTEM
212 void
213 BaseCPU::post_interrupt(int int_num, int index)
214 {
215 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
216
217 if (int_num < 0 || int_num >= NumInterruptLevels)
218 panic("int_num out of bounds\n");
219
220 if (index < 0 || index >= sizeof(uint64_t) * 8)
221 panic("int_num out of bounds\n");
222
223 checkInterrupts = true;
224 interrupts[int_num] |= 1 << index;
225 intstatus |= (ULL(1) << int_num);
226 }
227
228 void
229 BaseCPU::clear_interrupt(int int_num, int index)
230 {
231 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
232
233 if (int_num < 0 || int_num >= NumInterruptLevels)
234 panic("int_num out of bounds\n");
235
236 if (index < 0 || index >= sizeof(uint64_t) * 8)
237 panic("int_num out of bounds\n");
238
239 interrupts[int_num] &= ~(1 << index);
240 if (interrupts[int_num] == 0)
241 intstatus &= ~(ULL(1) << int_num);
242 }
243
244 void
245 BaseCPU::clear_interrupts()
246 {
247 DPRINTF(Interrupt, "Interrupts all cleared\n");
248
249 memset(interrupts, 0, sizeof(interrupts));
250 intstatus = 0;
251 }
252
253
254 void
255 BaseCPU::serialize(std::ostream &os)
256 {
257 SERIALIZE_ARRAY(interrupts, NumInterruptLevels);
258 SERIALIZE_SCALAR(intstatus);
259 }
260
261 void
262 BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
263 {
264 UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels);
265 UNSERIALIZE_SCALAR(intstatus);
266 }
267
268 #endif // FULL_SYSTEM
269
270 DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)