Updated Copyright with information in bitkeeper changelogs
[gem5.git] / dev / tsunami_cchip.cc
1 /*
2 * Copyright (c) 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 /* @file
30 * Emulation of the Tsunami CChip CSRs
31 */
32
33 #include <deque>
34 #include <string>
35 #include <vector>
36
37 #include "base/trace.hh"
38 #include "cpu/exec_context.hh"
39 #include "dev/console.hh"
40 #include "dev/tsunami_cchip.hh"
41 #include "dev/tsunamireg.h"
42 #include "dev/tsunami.hh"
43 #include "cpu/intr_control.hh"
44 #include "mem/functional_mem/memory_control.hh"
45 #include "sim/builder.hh"
46 #include "sim/system.hh"
47
48 using namespace std;
49
50 TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a,
51 MemoryController *mmu)
52 : FunctionalMemory(name), addr(a), tsunami(t)
53 {
54 mmu->add_child(this, Range<Addr>(addr, addr + size));
55
56 for(int i=0; i < Tsunami::Max_CPUs; i++) {
57 dim[i] = 0;
58 dir[i] = 0;
59 dirInterrupting[i] = false;
60 ipiInterrupting[i] = false;
61 RTCInterrupting[i] = false;
62 }
63
64 drir = 0;
65 misc = 0;
66
67 //Put back pointer in tsunami
68 tsunami->cchip = this;
69 }
70
71 Fault
72 TsunamiCChip::read(MemReqPtr &req, uint8_t *data)
73 {
74 DPRINTF(Tsunami, "read va=%#x size=%d\n",
75 req->vaddr, req->size);
76
77 Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
78 ExecContext *xc = req->xc;
79
80 switch (req->size) {
81
82 case sizeof(uint64_t):
83 switch(daddr) {
84 case TSDEV_CC_CSR:
85 *(uint64_t*)data = 0x0;
86 return No_Fault;
87 case TSDEV_CC_MTR:
88 panic("TSDEV_CC_MTR not implemeted\n");
89 return No_Fault;
90 case TSDEV_CC_MISC:
91 *(uint64_t*)data = misc | (xc->cpu_id & 0x3);
92 return No_Fault;
93 case TSDEV_CC_AAR0:
94 case TSDEV_CC_AAR1:
95 case TSDEV_CC_AAR2:
96 case TSDEV_CC_AAR3:
97 *(uint64_t*)data = 0;
98 return No_Fault;
99 case TSDEV_CC_DIM0:
100 *(uint64_t*)data = dim[0];
101 return No_Fault;
102 case TSDEV_CC_DIM1:
103 *(uint64_t*)data = dim[1];
104 return No_Fault;
105 case TSDEV_CC_DIM2:
106 *(uint64_t*)data = dim[2];
107 return No_Fault;
108 case TSDEV_CC_DIM3:
109 *(uint64_t*)data = dim[3];
110 return No_Fault;
111 case TSDEV_CC_DIR0:
112 *(uint64_t*)data = dir[0];
113 return No_Fault;
114 case TSDEV_CC_DIR1:
115 *(uint64_t*)data = dir[1];
116 return No_Fault;
117 case TSDEV_CC_DIR2:
118 *(uint64_t*)data = dir[2];
119 return No_Fault;
120 case TSDEV_CC_DIR3:
121 *(uint64_t*)data = dir[3];
122 return No_Fault;
123 case TSDEV_CC_DRIR:
124 *(uint64_t*)data = drir;
125 return No_Fault;
126 case TSDEV_CC_PRBEN:
127 panic("TSDEV_CC_PRBEN not implemented\n");
128 return No_Fault;
129 case TSDEV_CC_IIC0:
130 case TSDEV_CC_IIC1:
131 case TSDEV_CC_IIC2:
132 case TSDEV_CC_IIC3:
133 panic("TSDEV_CC_IICx not implemented\n");
134 return No_Fault;
135 case TSDEV_CC_MPR0:
136 case TSDEV_CC_MPR1:
137 case TSDEV_CC_MPR2:
138 case TSDEV_CC_MPR3:
139 panic("TSDEV_CC_MPRx not implemented\n");
140 return No_Fault;
141 default:
142 panic("default in cchip read reached, accessing 0x%x\n");
143 } // uint64_t
144
145 break;
146 case sizeof(uint32_t):
147 case sizeof(uint16_t):
148 case sizeof(uint8_t):
149 default:
150 panic("invalid access size(?) for tsunami register!\n");
151 }
152 DPRINTFN("Tsunami CChip ERROR: read daddr=%#x size=%d\n", daddr, req->size);
153
154 return No_Fault;
155 }
156
157 Fault
158 TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
159 {
160 DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n",
161 req->vaddr, *(uint64_t*)data, req->size);
162
163 Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
164
165 bool supportedWrite = false;
166 uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
167
168 switch (req->size) {
169
170 case sizeof(uint64_t):
171 switch(daddr) {
172 case TSDEV_CC_CSR:
173 panic("TSDEV_CC_CSR write\n");
174 return No_Fault;
175 case TSDEV_CC_MTR:
176 panic("TSDEV_CC_MTR write not implemented\n");
177 return No_Fault;
178 case TSDEV_CC_MISC:
179 //If it is the 4-7th bit, clear the RTC interrupt
180 uint64_t itintr;
181 if ((itintr = (*(uint64_t*) data) & (0xf<<4))) {
182 //Clear the bits in ITINTR
183 misc &= ~(itintr);
184 for (int i=0; i < size; i++) {
185 if ((itintr & (1 << (i+4))) && RTCInterrupting[i]) {
186 tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
187 RTCInterrupting[i] = false;
188 DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
189 }
190 }
191 supportedWrite = true;
192 }
193 //If it is 12th-15th bit, IPI sent to Processor 1
194 uint64_t ipreq;
195 if ((ipreq = (*(uint64_t*) data) & (0xf << 12))) {
196 //Set the bits in IPINTR
197 misc |= (ipreq >> 4);
198 for (int i=0; i < size; i++) {
199 if ((ipreq & (1 << (i + 12)))) {
200 if (!ipiInterrupting[i])
201 tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ3, 0);
202 ipiInterrupting[i]++;
203 DPRINTF(IPI, "send cpu=%d pending=%d from=%d\n", i,
204 ipiInterrupting[i], req->cpu_num);
205 }
206 }
207 supportedWrite = true;
208 }
209 //If it is bits 8-11, then clearing IPI's
210 uint64_t ipintr;
211 if ((ipintr = (*(uint64_t*) data) & (0xf << 8))) {
212 //Clear the bits in IPINTR
213 misc &= ~(ipintr);
214 for (int i=0; i < size; i++) {
215 if ((ipintr & (1 << (i + 8))) && ipiInterrupting[i]) {
216 if (!(--ipiInterrupting[i]))
217 tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ3, 0);
218 DPRINTF(IPI, "clearing cpu=%d pending=%d from=%d\n", i,
219 ipiInterrupting[i] + 1, req->cpu_num);
220 }
221 }
222 supportedWrite = true;
223 }
224
225 // ignore NXMs
226 if (*(uint64_t*)data & 0x10000000)
227 supportedWrite = true;
228
229 if(!supportedWrite) panic("TSDEV_CC_MISC write not implemented\n");
230 return No_Fault;
231 case TSDEV_CC_AAR0:
232 case TSDEV_CC_AAR1:
233 case TSDEV_CC_AAR2:
234 case TSDEV_CC_AAR3:
235 panic("TSDEV_CC_AARx write not implemeted\n");
236 return No_Fault;
237 case TSDEV_CC_DIM0:
238 case TSDEV_CC_DIM1:
239 case TSDEV_CC_DIM2:
240 case TSDEV_CC_DIM3:
241 int number;
242 if(daddr == TSDEV_CC_DIM0)
243 number = 0;
244 else if(daddr == TSDEV_CC_DIM1)
245 number = 1;
246 else if(daddr == TSDEV_CC_DIM2)
247 number = 2;
248 else
249 number = 3;
250
251 uint64_t bitvector;
252 uint64_t olddim;
253 uint64_t olddir;
254
255 olddim = dim[number];
256 olddir = dir[number];
257 dim[number] = *(uint64_t*)data;
258 dir[number] = dim[number] & drir;
259 for(int x = 0; x < 64; x++)
260 {
261 bitvector = (uint64_t)1 << x;
262 // Figure out which bits have changed
263 if ((dim[number] & bitvector) != (olddim & bitvector))
264 {
265 // The bit is now set and it wasn't before (set)
266 if((dim[number] & bitvector) && (dir[number] & bitvector))
267 {
268 tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
269 DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
270 }
271 else if ((olddir & bitvector) &&
272 !(dir[number] & bitvector))
273 {
274 // The bit was set and now its now clear and
275 // we were interrupting on that bit before
276 tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
277 DPRINTF(Tsunami, "dim write resulting in clear"
278 "dir interrupt to cpu 0\n");
279
280 }
281
282
283 }
284 }
285 return No_Fault;
286 case TSDEV_CC_DIR0:
287 case TSDEV_CC_DIR1:
288 case TSDEV_CC_DIR2:
289 case TSDEV_CC_DIR3:
290 panic("TSDEV_CC_DIR write not implemented\n");
291 case TSDEV_CC_DRIR:
292 panic("TSDEV_CC_DRIR write not implemented\n");
293 case TSDEV_CC_PRBEN:
294 panic("TSDEV_CC_PRBEN write not implemented\n");
295 case TSDEV_CC_IIC0:
296 case TSDEV_CC_IIC1:
297 case TSDEV_CC_IIC2:
298 case TSDEV_CC_IIC3:
299 panic("TSDEV_CC_IICx write not implemented\n");
300 case TSDEV_CC_MPR0:
301 case TSDEV_CC_MPR1:
302 case TSDEV_CC_MPR2:
303 case TSDEV_CC_MPR3:
304 panic("TSDEV_CC_MPRx write not implemented\n");
305 default:
306 panic("default in cchip read reached, accessing 0x%x\n");
307 }
308
309 break;
310 case sizeof(uint32_t):
311 case sizeof(uint16_t):
312 case sizeof(uint8_t):
313 default:
314 panic("invalid access size(?) for tsunami register!\n");
315 }
316
317 DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);
318
319 return No_Fault;
320 }
321
322 void
323 TsunamiCChip::postRTC()
324 {
325 int size = tsunami->intrctrl->cpu->system->execContexts.size();
326
327 for (int i = 0; i < size; i++) {
328 if (!RTCInterrupting[i]) {
329 misc |= 16 << i;
330 RTCInterrupting[i] = true;
331 tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
332 DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i);
333 }
334 }
335
336 }
337
338 void
339 TsunamiCChip::postDRIR(uint32_t interrupt)
340 {
341 uint64_t bitvector = (uint64_t)0x1 << interrupt;
342 drir |= bitvector;
343 uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
344 for(int i=0; i < size; i++) {
345 dir[i] = dim[i] & drir;
346 if (dim[i] & bitvector) {
347 tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
348 DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
349 "interrupt %d\n",i, interrupt);
350 }
351 }
352 }
353
354 void
355 TsunamiCChip::clearDRIR(uint32_t interrupt)
356 {
357 uint64_t bitvector = (uint64_t)0x1 << interrupt;
358 uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
359 if (drir & bitvector)
360 {
361 drir &= ~bitvector;
362 for(int i=0; i < size; i++) {
363 if (dir[i] & bitvector) {
364 tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
365 DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
366 "interrupt %d\n",i, interrupt);
367
368 }
369 dir[i] = dim[i] & drir;
370 }
371 }
372 else
373 DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
374 }
375
376 void
377 TsunamiCChip::serialize(std::ostream &os)
378 {
379 SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
380 SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
381 SERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
382 SERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
383 SERIALIZE_SCALAR(drir);
384 SERIALIZE_SCALAR(misc);
385 SERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
386 }
387
388 void
389 TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
390 {
391 UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
392 UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
393 UNSERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
394 UNSERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
395 UNSERIALIZE_SCALAR(drir);
396 UNSERIALIZE_SCALAR(misc);
397 UNSERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
398 }
399
400 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
401
402 SimObjectParam<Tsunami *> tsunami;
403 SimObjectParam<MemoryController *> mmu;
404 Param<Addr> addr;
405
406 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
407
408 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
409
410 INIT_PARAM(tsunami, "Tsunami"),
411 INIT_PARAM(mmu, "Memory Controller"),
412 INIT_PARAM(addr, "Device Address")
413
414 END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
415
416 CREATE_SIM_OBJECT(TsunamiCChip)
417 {
418 return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu);
419 }
420
421 REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)