Fix a small bug in parameter processing that would always result
[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, Range<Addr>(addr, 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(addr, addr + size - 1);
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 & PA_IMPL_MASK)) >> 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 & PA_IMPL_MASK)) >> 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 //If it is the 4-7th bit, clear the RTC interrupt
189 uint64_t itintr;
190 if ((itintr = (*(uint64_t*) data) & (0xf<<4))) {
191 //Clear the bits in ITINTR
192 misc &= ~(itintr);
193 for (int i=0; i < size; i++) {
194 if ((itintr & (1 << (i+4))) && RTCInterrupting[i]) {
195 tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
196 RTCInterrupting[i] = false;
197 DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
198 }
199 }
200 supportedWrite = true;
201 }
202 //If it is 12th-15th bit, IPI sent to Processor 1
203 uint64_t ipreq;
204 if ((ipreq = (*(uint64_t*) data) & (0xf << 12))) {
205 //Set the bits in IPINTR
206 misc |= (ipreq >> 4);
207 for (int i=0; i < size; i++) {
208 if ((ipreq & (1 << (i + 12)))) {
209 if (!ipiInterrupting[i])
210 tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ3, 0);
211 ipiInterrupting[i]++;
212 DPRINTF(IPI, "send cpu=%d pending=%d from=%d\n", i,
213 ipiInterrupting[i], req->cpu_num);
214 }
215 }
216 supportedWrite = true;
217 }
218 //If it is bits 8-11, then clearing IPI's
219 uint64_t ipintr;
220 if ((ipintr = (*(uint64_t*) data) & (0xf << 8))) {
221 //Clear the bits in IPINTR
222 misc &= ~(ipintr);
223 for (int i=0; i < size; i++) {
224 if ((ipintr & (1 << (i + 8))) && ipiInterrupting[i]) {
225 if (!(--ipiInterrupting[i]))
226 tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ3, 0);
227 DPRINTF(IPI, "clearing cpu=%d pending=%d from=%d\n", i,
228 ipiInterrupting[i] + 1, req->cpu_num);
229 }
230 }
231 supportedWrite = true;
232 }
233
234 // ignore NXMs
235 if (*(uint64_t*)data & 0x10000000)
236 supportedWrite = true;
237
238 if(!supportedWrite) panic("TSDEV_CC_MISC write not implemented\n");
239 return No_Fault;
240 case TSDEV_CC_AAR0:
241 case TSDEV_CC_AAR1:
242 case TSDEV_CC_AAR2:
243 case TSDEV_CC_AAR3:
244 panic("TSDEV_CC_AARx write not implemeted\n");
245 return No_Fault;
246 case TSDEV_CC_DIM0:
247 case TSDEV_CC_DIM1:
248 case TSDEV_CC_DIM2:
249 case TSDEV_CC_DIM3:
250 int number;
251 if(daddr == TSDEV_CC_DIM0)
252 number = 0;
253 else if(daddr == TSDEV_CC_DIM1)
254 number = 1;
255 else if(daddr == TSDEV_CC_DIM2)
256 number = 2;
257 else
258 number = 3;
259
260 uint64_t bitvector;
261 uint64_t olddim;
262 uint64_t olddir;
263
264 olddim = dim[number];
265 olddir = dir[number];
266 dim[number] = *(uint64_t*)data;
267 dir[number] = dim[number] & drir;
268 for(int x = 0; x < 64; x++)
269 {
270 bitvector = (uint64_t)1 << x;
271 // Figure out which bits have changed
272 if ((dim[number] & bitvector) != (olddim & bitvector))
273 {
274 // The bit is now set and it wasn't before (set)
275 if((dim[number] & bitvector) && (dir[number] & bitvector))
276 {
277 tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
278 DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
279 }
280 else if ((olddir & bitvector) &&
281 !(dir[number] & bitvector))
282 {
283 // The bit was set and now its now clear and
284 // we were interrupting on that bit before
285 tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
286 DPRINTF(Tsunami, "dim write resulting in clear"
287 "dir interrupt to cpu 0\n");
288
289 }
290
291
292 }
293 }
294 return No_Fault;
295 case TSDEV_CC_DIR0:
296 case TSDEV_CC_DIR1:
297 case TSDEV_CC_DIR2:
298 case TSDEV_CC_DIR3:
299 panic("TSDEV_CC_DIR write not implemented\n");
300 case TSDEV_CC_DRIR:
301 panic("TSDEV_CC_DRIR write not implemented\n");
302 case TSDEV_CC_PRBEN:
303 panic("TSDEV_CC_PRBEN write not implemented\n");
304 case TSDEV_CC_IIC0:
305 case TSDEV_CC_IIC1:
306 case TSDEV_CC_IIC2:
307 case TSDEV_CC_IIC3:
308 panic("TSDEV_CC_IICx write not implemented\n");
309 case TSDEV_CC_MPR0:
310 case TSDEV_CC_MPR1:
311 case TSDEV_CC_MPR2:
312 case TSDEV_CC_MPR3:
313 panic("TSDEV_CC_MPRx write not implemented\n");
314 default:
315 panic("default in cchip read reached, accessing 0x%x\n");
316 }
317
318 break;
319 case sizeof(uint32_t):
320 case sizeof(uint16_t):
321 case sizeof(uint8_t):
322 default:
323 panic("invalid access size(?) for tsunami register!\n");
324 }
325
326 DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);
327
328 return No_Fault;
329 }
330
331 void
332 TsunamiCChip::postRTC()
333 {
334 int size = tsunami->intrctrl->cpu->system->execContexts.size();
335
336 for (int i = 0; i < size; i++) {
337 if (!RTCInterrupting[i]) {
338 misc |= 16 << i;
339 RTCInterrupting[i] = true;
340 tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
341 DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i);
342 }
343 }
344
345 }
346
347 void
348 TsunamiCChip::postDRIR(uint32_t interrupt)
349 {
350 uint64_t bitvector = (uint64_t)0x1 << interrupt;
351 drir |= bitvector;
352 uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
353 for(int i=0; i < size; i++) {
354 dir[i] = dim[i] & drir;
355 if (dim[i] & bitvector) {
356 tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
357 DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
358 "interrupt %d\n",i, interrupt);
359 }
360 }
361 }
362
363 void
364 TsunamiCChip::clearDRIR(uint32_t interrupt)
365 {
366 uint64_t bitvector = (uint64_t)0x1 << interrupt;
367 uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
368 if (drir & bitvector)
369 {
370 drir &= ~bitvector;
371 for(int i=0; i < size; i++) {
372 if (dir[i] & bitvector) {
373 tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
374 DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
375 "interrupt %d\n",i, interrupt);
376
377 }
378 dir[i] = dim[i] & drir;
379 }
380 }
381 else
382 DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
383 }
384
385 Tick
386 TsunamiCChip::cacheAccess(MemReqPtr &req)
387 {
388 return curTick + pioLatency;
389 }
390
391
392 void
393 TsunamiCChip::serialize(std::ostream &os)
394 {
395 SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
396 SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
397 SERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
398 SERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
399 SERIALIZE_SCALAR(drir);
400 SERIALIZE_SCALAR(misc);
401 SERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
402 }
403
404 void
405 TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
406 {
407 UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
408 UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
409 UNSERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
410 UNSERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
411 UNSERIALIZE_SCALAR(drir);
412 UNSERIALIZE_SCALAR(misc);
413 UNSERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
414 }
415
416 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
417
418 SimObjectParam<Tsunami *> tsunami;
419 SimObjectParam<MemoryController *> mmu;
420 Param<Addr> addr;
421 SimObjectParam<Bus*> io_bus;
422 Param<Tick> pio_latency;
423 SimObjectParam<HierParams *> hier;
424
425 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
426
427 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
428
429 INIT_PARAM(tsunami, "Tsunami"),
430 INIT_PARAM(mmu, "Memory Controller"),
431 INIT_PARAM(addr, "Device Address"),
432 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
433 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
434 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
435
436 END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
437
438 CREATE_SIM_OBJECT(TsunamiCChip)
439 {
440 return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu, hier,
441 io_bus, pio_latency);
442 }
443
444 REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)