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