iob.cc (4216:c01745179a1f) iob.cc (4762:c94e103c83ad)
1/*
2 * Copyright (c) 2006 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 * Authors: Ali Saidi
29 */
30
31/** @file
32 * This device implemetns the niagara I/O bridge chip. It manages incomming
33 * interrupts and posts them to the CPU when needed. It holds mask registers and
34 * various status registers for CPUs to check what interrupts are pending as
35 * well as facilities to send IPIs to other cpus.
36 */
37
38#include <cstring>
39
40#include "arch/sparc/isa_traits.hh"
41#include "arch/sparc/faults.hh"
42#include "base/trace.hh"
43#include "cpu/intr_control.hh"
44#include "dev/sparc/iob.hh"
45#include "dev/platform.hh"
46#include "mem/port.hh"
47#include "mem/packet_access.hh"
1/*
2 * Copyright (c) 2006 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 * Authors: Ali Saidi
29 */
30
31/** @file
32 * This device implemetns the niagara I/O bridge chip. It manages incomming
33 * interrupts and posts them to the CPU when needed. It holds mask registers and
34 * various status registers for CPUs to check what interrupts are pending as
35 * well as facilities to send IPIs to other cpus.
36 */
37
38#include <cstring>
39
40#include "arch/sparc/isa_traits.hh"
41#include "arch/sparc/faults.hh"
42#include "base/trace.hh"
43#include "cpu/intr_control.hh"
44#include "dev/sparc/iob.hh"
45#include "dev/platform.hh"
46#include "mem/port.hh"
47#include "mem/packet_access.hh"
48#include "sim/builder.hh"
49#include "sim/faults.hh"
50#include "sim/system.hh"
51
48#include "sim/faults.hh"
49#include "sim/system.hh"
50
52Iob::Iob(Params *p)
51Iob::Iob(const Params *p)
53 : PioDevice(p), ic(p->platform->intrctrl)
54{
55 iobManAddr = ULL(0x9800000000);
56 iobManSize = ULL(0x0100000000);
57 iobJBusAddr = ULL(0x9F00000000);
58 iobJBusSize = ULL(0x0100000000);
59 assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
60 // Get the interrupt controller from the platform
61 ic = platform->intrctrl;
62
63 for (int x = 0; x < NumDeviceIds; ++x) {
64 intMan[x].cpu = 0;
65 intMan[x].vector = 0;
66 intCtl[x].mask = true;
67 intCtl[x].pend = false;
68 }
69
70}
71
72Tick
73Iob::read(PacketPtr pkt)
74{
75 assert(pkt->result == Packet::Unknown);
76
77 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
78 readIob(pkt);
79 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
80 readJBus(pkt);
81 else
82 panic("Invalid address reached Iob\n");
83
84 pkt->result = Packet::Success;
85 return pioDelay;
86}
87
88void
89Iob::readIob(PacketPtr pkt)
90{
91 Addr accessAddr = pkt->getAddr() - iobManAddr;
92 int index;
93 uint64_t data;
94
95 if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
96 index = (accessAddr - IntManAddr) >> 3;
97 data = intMan[index].cpu << 8 | intMan[index].vector << 0;
98 pkt->set(data);
99 return;
100 }
101
102 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
103 index = (accessAddr - IntManAddr) >> 3;
104 data = intCtl[index].mask ? 1 << 2 : 0 |
105 intCtl[index].pend ? 1 << 0 : 0;
106 pkt->set(data);
107 return;
108 }
109
110 if (accessAddr == JIntVecAddr) {
111 pkt->set(jIntVec);
112 return;
113 }
114
115 panic("Read to unknown IOB offset 0x%x\n", accessAddr);
116}
117
118void
119Iob::readJBus(PacketPtr pkt)
120{
121 Addr accessAddr = pkt->getAddr() - iobJBusAddr;
122 int cpuid = pkt->req->getCpuNum();
123 int index;
124 uint64_t data;
125
126
127
128
129 if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) {
130 index = (accessAddr - JIntData0Addr) >> 3;
131 pkt->set(jBusData0[index]);
132 return;
133 }
134
135 if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
136 index = (accessAddr - JIntData1Addr) >> 3;
137 pkt->set(jBusData1[index]);
138 return;
139 }
140
141 if (accessAddr == JIntDataA0Addr) {
142 pkt->set(jBusData0[cpuid]);
143 return;
144 }
145
146 if (accessAddr == JIntDataA1Addr) {
147 pkt->set(jBusData1[cpuid]);
148 return;
149 }
150
151 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
152 index = (accessAddr - JIntBusyAddr) >> 3;
153 data = jIntBusy[index].busy ? 1 << 5 : 0 |
154 jIntBusy[index].source;
155 pkt->set(data);
156 return;
157 }
158 if (accessAddr == JIntABusyAddr) {
159 data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
160 jIntBusy[cpuid].source;
161 pkt->set(data);
162 return;
163 };
164
165 panic("Read to unknown JBus offset 0x%x\n", accessAddr);
166}
167
168Tick
169Iob::write(PacketPtr pkt)
170{
171 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
172 writeIob(pkt);
173 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
174 writeJBus(pkt);
175 else
176 panic("Invalid address reached Iob\n");
177
178
179 pkt->result = Packet::Success;
180 return pioDelay;
181}
182
183void
184Iob::writeIob(PacketPtr pkt)
185{
186 Addr accessAddr = pkt->getAddr() - iobManAddr;
187 int index;
188 uint64_t data;
189
190 if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
191 index = (accessAddr - IntManAddr) >> 3;
192 data = pkt->get<uint64_t>();
193 intMan[index].cpu = bits(data,12,8);
194 intMan[index].vector = bits(data,5,0);
195 DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index,
196 intMan[index].cpu, intMan[index].vector);
197 return;
198 }
199
200 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
201 index = (accessAddr - IntManAddr) >> 3;
202 data = pkt->get<uint64_t>();
203 intCtl[index].mask = bits(data,2,2);
204 if (bits(data,1,1))
205 intCtl[index].pend = false;
206 DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index,
207 intCtl[index].pend, bits(data,2,2));
208 return;
209 }
210
211 if (accessAddr == JIntVecAddr) {
212 jIntVec = bits(pkt->get<uint64_t>(), 5,0);
213 DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec);
214 return;
215 }
216
217 if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
218 Type type;
219 int cpu_id;
220 int vector;
221 index = (accessAddr - IntManAddr) >> 3;
222 data = pkt->get<uint64_t>();
223 type = (Type)bits(data,17,16);
224 cpu_id = bits(data, 12,8);
225 vector = bits(data,5,0);
226 generateIpi(type,cpu_id, vector);
227 return;
228 }
229
230 panic("Write to unknown IOB offset 0x%x\n", accessAddr);
231}
232
233void
234Iob::writeJBus(PacketPtr pkt)
235{
236 Addr accessAddr = pkt->getAddr() - iobJBusAddr;
237 int cpuid = pkt->req->getCpuNum();
238 int index;
239 uint64_t data;
240
241 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
242 index = (accessAddr - JIntBusyAddr) >> 3;
243 data = pkt->get<uint64_t>();
244 jIntBusy[index].busy = bits(data,5,5);
245 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index,
246 jIntBusy[index].busy);
247 return;
248 }
249 if (accessAddr == JIntABusyAddr) {
250 data = pkt->get<uint64_t>();
251 jIntBusy[cpuid].busy = bits(data,5,5);
252 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid,
253 jIntBusy[cpuid].busy);
254 return;
255 };
256
257 panic("Write to unknown JBus offset 0x%x\n", accessAddr);
258}
259
260void
261Iob::receiveDeviceInterrupt(DeviceId devid)
262{
263 assert(devid < NumDeviceIds);
264 if (intCtl[devid].mask)
265 return;
266 intCtl[devid].mask = true;
267 intCtl[devid].pend = true;
268 DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n",
269 devid, intMan[devid].cpu, intMan[devid].vector);
270 ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
271}
272
273
274void
275Iob::generateIpi(Type type, int cpu_id, int vector)
276{
277 SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
278 if (cpu_id >= sys->getNumCPUs())
279 return;
280
281 switch (type) {
282 case 0: // interrupt
283 DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
284 cpu_id, vector);
285 ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
286 break;
287 case 1: // reset
288 warn("Sending reset to CPU: %d\n", cpu_id);
289 if (vector != por->trapType())
290 panic("Don't know how to set non-POR reset to cpu\n");
291 por->invoke(sys->threadContexts[cpu_id]);
292 sys->threadContexts[cpu_id]->activate();
293 break;
294 case 2: // idle -- this means stop executing and don't wake on interrupts
295 DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id);
296 sys->threadContexts[cpu_id]->halt();
297 break;
298 case 3: // resume
299 DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
300 sys->threadContexts[cpu_id]->activate();
301 break;
302 default:
303 panic("Invalid type to generate ipi\n");
304 }
305}
306
307bool
308Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
309{
310 // If we are already dealing with an interrupt for that cpu we can't deal
311 // with another one right now... come back later
312 if (jIntBusy[cpu_id].busy)
313 return false;
314
315 DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
316 source, cpu_id, jIntVec);
317
318 jIntBusy[cpu_id].busy = true;
319 jIntBusy[cpu_id].source = source;
320 jBusData0[cpu_id] = d0;
321 jBusData1[cpu_id] = d1;
322
323 ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
324 return true;
325}
326
327void
328Iob::addressRanges(AddrRangeList &range_list)
329{
330 range_list.clear();
331 range_list.push_back(RangeSize(iobManAddr, iobManSize));
332 range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize));
333}
334
335
336void
337Iob::serialize(std::ostream &os)
338{
339
340 SERIALIZE_SCALAR(jIntVec);
341 SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
342 SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
343 for (int x = 0; x < NumDeviceIds; x++) {
344 nameOut(os, csprintf("%s.Int%d", name(), x));
345 paramOut(os, "cpu", intMan[x].cpu);
346 paramOut(os, "vector", intMan[x].vector);
347 paramOut(os, "mask", intCtl[x].mask);
348 paramOut(os, "pend", intCtl[x].pend);
349 };
350 for (int x = 0; x < MaxNiagaraProcs; x++) {
351 nameOut(os, csprintf("%s.jIntBusy%d", name(), x));
352 paramOut(os, "busy", jIntBusy[x].busy);
353 paramOut(os, "source", jIntBusy[x].source);
354 };
355}
356
357void
358Iob::unserialize(Checkpoint *cp, const std::string &section)
359{
360 UNSERIALIZE_SCALAR(jIntVec);
361 UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
362 UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
363 for (int x = 0; x < NumDeviceIds; x++) {
364 paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu);
365 paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector);
366 paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask);
367 paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend);
368 };
369 for (int x = 0; x < MaxNiagaraProcs; x++) {
370 paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy);
371 paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source);
372 };
373}
374
52 : PioDevice(p), ic(p->platform->intrctrl)
53{
54 iobManAddr = ULL(0x9800000000);
55 iobManSize = ULL(0x0100000000);
56 iobJBusAddr = ULL(0x9F00000000);
57 iobJBusSize = ULL(0x0100000000);
58 assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
59 // Get the interrupt controller from the platform
60 ic = platform->intrctrl;
61
62 for (int x = 0; x < NumDeviceIds; ++x) {
63 intMan[x].cpu = 0;
64 intMan[x].vector = 0;
65 intCtl[x].mask = true;
66 intCtl[x].pend = false;
67 }
68
69}
70
71Tick
72Iob::read(PacketPtr pkt)
73{
74 assert(pkt->result == Packet::Unknown);
75
76 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
77 readIob(pkt);
78 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
79 readJBus(pkt);
80 else
81 panic("Invalid address reached Iob\n");
82
83 pkt->result = Packet::Success;
84 return pioDelay;
85}
86
87void
88Iob::readIob(PacketPtr pkt)
89{
90 Addr accessAddr = pkt->getAddr() - iobManAddr;
91 int index;
92 uint64_t data;
93
94 if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
95 index = (accessAddr - IntManAddr) >> 3;
96 data = intMan[index].cpu << 8 | intMan[index].vector << 0;
97 pkt->set(data);
98 return;
99 }
100
101 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
102 index = (accessAddr - IntManAddr) >> 3;
103 data = intCtl[index].mask ? 1 << 2 : 0 |
104 intCtl[index].pend ? 1 << 0 : 0;
105 pkt->set(data);
106 return;
107 }
108
109 if (accessAddr == JIntVecAddr) {
110 pkt->set(jIntVec);
111 return;
112 }
113
114 panic("Read to unknown IOB offset 0x%x\n", accessAddr);
115}
116
117void
118Iob::readJBus(PacketPtr pkt)
119{
120 Addr accessAddr = pkt->getAddr() - iobJBusAddr;
121 int cpuid = pkt->req->getCpuNum();
122 int index;
123 uint64_t data;
124
125
126
127
128 if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) {
129 index = (accessAddr - JIntData0Addr) >> 3;
130 pkt->set(jBusData0[index]);
131 return;
132 }
133
134 if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
135 index = (accessAddr - JIntData1Addr) >> 3;
136 pkt->set(jBusData1[index]);
137 return;
138 }
139
140 if (accessAddr == JIntDataA0Addr) {
141 pkt->set(jBusData0[cpuid]);
142 return;
143 }
144
145 if (accessAddr == JIntDataA1Addr) {
146 pkt->set(jBusData1[cpuid]);
147 return;
148 }
149
150 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
151 index = (accessAddr - JIntBusyAddr) >> 3;
152 data = jIntBusy[index].busy ? 1 << 5 : 0 |
153 jIntBusy[index].source;
154 pkt->set(data);
155 return;
156 }
157 if (accessAddr == JIntABusyAddr) {
158 data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
159 jIntBusy[cpuid].source;
160 pkt->set(data);
161 return;
162 };
163
164 panic("Read to unknown JBus offset 0x%x\n", accessAddr);
165}
166
167Tick
168Iob::write(PacketPtr pkt)
169{
170 if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
171 writeIob(pkt);
172 else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
173 writeJBus(pkt);
174 else
175 panic("Invalid address reached Iob\n");
176
177
178 pkt->result = Packet::Success;
179 return pioDelay;
180}
181
182void
183Iob::writeIob(PacketPtr pkt)
184{
185 Addr accessAddr = pkt->getAddr() - iobManAddr;
186 int index;
187 uint64_t data;
188
189 if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
190 index = (accessAddr - IntManAddr) >> 3;
191 data = pkt->get<uint64_t>();
192 intMan[index].cpu = bits(data,12,8);
193 intMan[index].vector = bits(data,5,0);
194 DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index,
195 intMan[index].cpu, intMan[index].vector);
196 return;
197 }
198
199 if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
200 index = (accessAddr - IntManAddr) >> 3;
201 data = pkt->get<uint64_t>();
202 intCtl[index].mask = bits(data,2,2);
203 if (bits(data,1,1))
204 intCtl[index].pend = false;
205 DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index,
206 intCtl[index].pend, bits(data,2,2));
207 return;
208 }
209
210 if (accessAddr == JIntVecAddr) {
211 jIntVec = bits(pkt->get<uint64_t>(), 5,0);
212 DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec);
213 return;
214 }
215
216 if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
217 Type type;
218 int cpu_id;
219 int vector;
220 index = (accessAddr - IntManAddr) >> 3;
221 data = pkt->get<uint64_t>();
222 type = (Type)bits(data,17,16);
223 cpu_id = bits(data, 12,8);
224 vector = bits(data,5,0);
225 generateIpi(type,cpu_id, vector);
226 return;
227 }
228
229 panic("Write to unknown IOB offset 0x%x\n", accessAddr);
230}
231
232void
233Iob::writeJBus(PacketPtr pkt)
234{
235 Addr accessAddr = pkt->getAddr() - iobJBusAddr;
236 int cpuid = pkt->req->getCpuNum();
237 int index;
238 uint64_t data;
239
240 if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
241 index = (accessAddr - JIntBusyAddr) >> 3;
242 data = pkt->get<uint64_t>();
243 jIntBusy[index].busy = bits(data,5,5);
244 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index,
245 jIntBusy[index].busy);
246 return;
247 }
248 if (accessAddr == JIntABusyAddr) {
249 data = pkt->get<uint64_t>();
250 jIntBusy[cpuid].busy = bits(data,5,5);
251 DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid,
252 jIntBusy[cpuid].busy);
253 return;
254 };
255
256 panic("Write to unknown JBus offset 0x%x\n", accessAddr);
257}
258
259void
260Iob::receiveDeviceInterrupt(DeviceId devid)
261{
262 assert(devid < NumDeviceIds);
263 if (intCtl[devid].mask)
264 return;
265 intCtl[devid].mask = true;
266 intCtl[devid].pend = true;
267 DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n",
268 devid, intMan[devid].cpu, intMan[devid].vector);
269 ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
270}
271
272
273void
274Iob::generateIpi(Type type, int cpu_id, int vector)
275{
276 SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
277 if (cpu_id >= sys->getNumCPUs())
278 return;
279
280 switch (type) {
281 case 0: // interrupt
282 DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
283 cpu_id, vector);
284 ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
285 break;
286 case 1: // reset
287 warn("Sending reset to CPU: %d\n", cpu_id);
288 if (vector != por->trapType())
289 panic("Don't know how to set non-POR reset to cpu\n");
290 por->invoke(sys->threadContexts[cpu_id]);
291 sys->threadContexts[cpu_id]->activate();
292 break;
293 case 2: // idle -- this means stop executing and don't wake on interrupts
294 DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id);
295 sys->threadContexts[cpu_id]->halt();
296 break;
297 case 3: // resume
298 DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
299 sys->threadContexts[cpu_id]->activate();
300 break;
301 default:
302 panic("Invalid type to generate ipi\n");
303 }
304}
305
306bool
307Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
308{
309 // If we are already dealing with an interrupt for that cpu we can't deal
310 // with another one right now... come back later
311 if (jIntBusy[cpu_id].busy)
312 return false;
313
314 DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
315 source, cpu_id, jIntVec);
316
317 jIntBusy[cpu_id].busy = true;
318 jIntBusy[cpu_id].source = source;
319 jBusData0[cpu_id] = d0;
320 jBusData1[cpu_id] = d1;
321
322 ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
323 return true;
324}
325
326void
327Iob::addressRanges(AddrRangeList &range_list)
328{
329 range_list.clear();
330 range_list.push_back(RangeSize(iobManAddr, iobManSize));
331 range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize));
332}
333
334
335void
336Iob::serialize(std::ostream &os)
337{
338
339 SERIALIZE_SCALAR(jIntVec);
340 SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
341 SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
342 for (int x = 0; x < NumDeviceIds; x++) {
343 nameOut(os, csprintf("%s.Int%d", name(), x));
344 paramOut(os, "cpu", intMan[x].cpu);
345 paramOut(os, "vector", intMan[x].vector);
346 paramOut(os, "mask", intCtl[x].mask);
347 paramOut(os, "pend", intCtl[x].pend);
348 };
349 for (int x = 0; x < MaxNiagaraProcs; x++) {
350 nameOut(os, csprintf("%s.jIntBusy%d", name(), x));
351 paramOut(os, "busy", jIntBusy[x].busy);
352 paramOut(os, "source", jIntBusy[x].source);
353 };
354}
355
356void
357Iob::unserialize(Checkpoint *cp, const std::string &section)
358{
359 UNSERIALIZE_SCALAR(jIntVec);
360 UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
361 UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
362 for (int x = 0; x < NumDeviceIds; x++) {
363 paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu);
364 paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector);
365 paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask);
366 paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend);
367 };
368 for (int x = 0; x < MaxNiagaraProcs; x++) {
369 paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy);
370 paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source);
371 };
372}
373
375
376
377
378BEGIN_DECLARE_SIM_OBJECT_PARAMS(Iob)
379 Param<Tick> pio_latency;
380 SimObjectParam<Platform *> platform;
381 SimObjectParam<System *> system;
382END_DECLARE_SIM_OBJECT_PARAMS(Iob)
383
384BEGIN_INIT_SIM_OBJECT_PARAMS(Iob)
385
386 INIT_PARAM(pio_latency, "Programmed IO latency"),
387 INIT_PARAM(platform, "platform"),
388 INIT_PARAM(system, "system object")
389
390END_INIT_SIM_OBJECT_PARAMS(Iob)
391
392CREATE_SIM_OBJECT(Iob)
374Iob *
375IobParams::create()
393{
376{
394 Iob::Params *p = new Iob::Params;
395 p->name = getInstanceName();
396 p->pio_delay = pio_latency;
397 p->platform = platform;
398 p->system = system;
399 return new Iob(p);
377 return new Iob(this);
400}
378}
401
402REGISTER_SIM_OBJECT("Iob", Iob)