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