iob.cc revision 4104
112SN/A/*
210037SARM gem5 Developers * Copyright (c) 2006 The Regents of The University of Michigan
310037SARM gem5 Developers * All rights reserved.
410037SARM gem5 Developers *
510037SARM gem5 Developers * Redistribution and use in source and binary forms, with or without
610037SARM gem5 Developers * modification, are permitted provided that the following conditions are
710037SARM gem5 Developers * met: redistributions of source code must retain the above copyright
810037SARM gem5 Developers * notice, this list of conditions and the following disclaimer;
910037SARM gem5 Developers * redistributions in binary form must reproduce the above copyright
1010037SARM gem5 Developers * notice, this list of conditions and the following disclaimer in the
1110037SARM gem5 Developers * documentation and/or other materials provided with the distribution;
1210037SARM gem5 Developers * neither the name of the copyright holders nor the names of its
1310037SARM gem5 Developers * contributors may be used to endorse or promote products derived from
141762SN/A * this software without specific prior written permission.
1512SN/A *
1612SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712SN/A *
2812SN/A * Authors: Ali Saidi
2912SN/A */
3012SN/A
3112SN/A/** @file
3212SN/A * This device implemetns the niagara I/O bridge chip. It manages incomming
3312SN/A * interrupts and posts them to the CPU when needed. It holds mask registers and
3412SN/A * various status registers for CPUs to check what interrupts are pending as
3512SN/A * well as facilities to send IPIs to other cpus.
3612SN/A */
3712SN/A
3812SN/A#include <cstring>
392665Ssaidi@eecs.umich.edu
402665Ssaidi@eecs.umich.edu#include "arch/sparc/isa_traits.hh"
4112SN/A#include "base/trace.hh"
4212SN/A#include "cpu/intr_control.hh"
4312SN/A#include "dev/sparc/iob.hh"
4412SN/A#include "dev/platform.hh"
4512SN/A#include "mem/port.hh"
465070Ssaidi@eecs.umich.edu#include "mem/packet_access.hh"
475090Sgblack@eecs.umich.edu#include "sim/builder.hh"
4812SN/A#include "sim/system.hh"
498229Snate@binkert.org
508229Snate@binkert.orgIob::Iob(Params *p)
5112SN/A    : PioDevice(p), ic(p->platform->intrctrl)
5212SN/A{
5312SN/A    iobManAddr = ULL(0x9800000000);
5412SN/A    iobManSize = ULL(0x0100000000);
555090Sgblack@eecs.umich.edu    iobJBusAddr = ULL(0x9F00000000);
565090Sgblack@eecs.umich.edu    iobJBusSize = ULL(0x0100000000);
575090Sgblack@eecs.umich.edu    assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
582976Sgblack@eecs.umich.edu    // Get the interrupt controller from the platform
592976Sgblack@eecs.umich.edu    ic = platform->intrctrl;
602976Sgblack@eecs.umich.edu
612976Sgblack@eecs.umich.edu    for (int x = 0; x < NumDeviceIds; ++x) {
622976Sgblack@eecs.umich.edu        intMan[x].cpu = 0;
635070Ssaidi@eecs.umich.edu        intMan[x].vector = 0;
642976Sgblack@eecs.umich.edu        intCtl[x].mask = true;
65468SN/A        intCtl[x].pend = false;
667581SAli.Saidi@arm.com    }
67468SN/A
6810880SCurtis.Dunham@arm.com}
69360SN/A
7012SN/ATick
715070Ssaidi@eecs.umich.eduIob::read(PacketPtr pkt)
725070Ssaidi@eecs.umich.edu{
735070Ssaidi@eecs.umich.edu    assert(pkt->result == Packet::Unknown);
745090Sgblack@eecs.umich.edu
755090Sgblack@eecs.umich.edu    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
7612SN/A        readIob(pkt);
7712SN/A    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
7812SN/A        readJBus(pkt);
798852Sandreas.hansson@arm.com    else
8010037SARM gem5 Developers        panic("Invalid address reached Iob\n");
8110037SARM gem5 Developers
823812Ssaidi@eecs.umich.edu    pkt->result = Packet::Success;
833812Ssaidi@eecs.umich.edu    return pioDelay;
843812Ssaidi@eecs.umich.edu}
853812Ssaidi@eecs.umich.edu
869641Sguodeyuan@tsinghua.org.cnvoid
879641Sguodeyuan@tsinghua.org.cnIob::readIob(PacketPtr pkt)
8812SN/A{
895070Ssaidi@eecs.umich.edu        Addr accessAddr = pkt->getAddr() - iobManAddr;
905070Ssaidi@eecs.umich.edu        int index;
913917Ssaidi@eecs.umich.edu        uint64_t data;
9210880SCurtis.Dunham@arm.com
9312SN/A        if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
942976Sgblack@eecs.umich.edu            index = (accessAddr - IntManAddr) >> 3;
952976Sgblack@eecs.umich.edu            data = intMan[index].cpu << 8 | intMan[index].vector << 0;
962976Sgblack@eecs.umich.edu            pkt->set(data);
9712SN/A            return;
9812SN/A        }
9912SN/A
100        if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
101            index = (accessAddr - IntManAddr) >> 3;
102            data = intCtl[index].mask  ? 1 << 2 : 0 |
103                   intCtl[index].pend  ? 1 << 0 : 0;
104            pkt->set(data);
105            return;
106        }
107
108        if (accessAddr == JIntVecAddr) {
109            pkt->set(jIntVec);
110            return;
111        }
112
113        panic("Read to unknown IOB offset 0x%x\n", accessAddr);
114}
115
116void
117Iob::readJBus(PacketPtr pkt)
118{
119        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
120        int cpuid = pkt->req->getCpuNum();
121        int index;
122        uint64_t data;
123
124
125
126
127        if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) {
128            index = (accessAddr - JIntData0Addr) >> 3;
129            pkt->set(jBusData0[index]);
130            return;
131        }
132
133        if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
134            index = (accessAddr - JIntData1Addr) >> 3;
135            pkt->set(jBusData1[index]);
136            return;
137        }
138
139        if (accessAddr == JIntDataA0Addr) {
140            pkt->set(jBusData0[cpuid]);
141            return;
142        }
143
144        if (accessAddr == JIntDataA1Addr) {
145            pkt->set(jBusData1[cpuid]);
146            return;
147        }
148
149        if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
150            index = (accessAddr - JIntBusyAddr) >> 3;
151            data = jIntBusy[index].busy ? 1 << 5 : 0 |
152                   jIntBusy[index].source;
153            pkt->set(data);
154            return;
155        }
156        if (accessAddr == JIntABusyAddr) {
157            data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
158                   jIntBusy[cpuid].source;
159            pkt->set(data);
160            return;
161        };
162
163        panic("Read to unknown JBus offset 0x%x\n", accessAddr);
164}
165
166Tick
167Iob::write(PacketPtr pkt)
168{
169    if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
170        writeIob(pkt);
171    else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
172        writeJBus(pkt);
173    else
174        panic("Invalid address reached Iob\n");
175
176
177    pkt->result = Packet::Success;
178    return pioDelay;
179}
180
181void
182Iob::writeIob(PacketPtr pkt)
183{
184        Addr accessAddr = pkt->getAddr() - iobManAddr;
185        int index;
186        uint64_t data;
187
188        if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
189            index = (accessAddr - IntManAddr) >> 3;
190            data = pkt->get<uint64_t>();
191            intMan[index].cpu = bits(data,12,8);
192            intMan[index].vector = bits(data,5,0);
193            return;
194        }
195
196        if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
197            index = (accessAddr - IntManAddr) >> 3;
198            data = pkt->get<uint64_t>();
199            intCtl[index].mask = bits(data,2,2);
200            if (bits(data,1,1))
201                intCtl[index].pend = false;
202            return;
203        }
204
205        if (accessAddr == JIntVecAddr) {
206            jIntVec = bits(pkt->get<uint64_t>(), 5,0);
207            return;
208        }
209
210        if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
211            Type type;
212            int cpu_id;
213            int vector;
214            index = (accessAddr - IntManAddr) >> 3;
215            data = pkt->get<uint64_t>();
216            type = (Type)bits(data,17,16);
217            cpu_id = bits(data, 12,8);
218            vector = bits(data,5,0);
219            generateIpi(type,cpu_id, vector);
220            return;
221        }
222
223        panic("Write to unknown IOB offset 0x%x\n", accessAddr);
224}
225
226void
227Iob::writeJBus(PacketPtr pkt)
228{
229        Addr accessAddr = pkt->getAddr() - iobJBusAddr;
230        int cpuid = pkt->req->getCpuNum();
231        int index;
232        uint64_t data;
233
234        if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
235            index = (accessAddr - JIntBusyAddr) >> 3;
236            data = pkt->get<uint64_t>();
237            jIntBusy[index].busy = bits(data,5,5);
238            return;
239        }
240        if (accessAddr == JIntABusyAddr) {
241            data = pkt->get<uint64_t>();
242            jIntBusy[cpuid].busy = bits(data,5,5);
243            return;
244        };
245
246        panic("Write to unknown JBus offset 0x%x\n", accessAddr);
247}
248
249void
250Iob::receiveDeviceInterrupt(DeviceId devid)
251{
252    assert(devid < NumDeviceIds);
253    if (intCtl[devid].mask)
254        return;
255    intCtl[devid].mask = true;
256    intCtl[devid].pend = true;
257    ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
258}
259
260
261void
262Iob::generateIpi(Type type, int cpu_id, int vector)
263{
264    // Only handle interrupts for the moment... Cpu Idle/reset/resume will be
265    // later
266    if (type != 0) {
267        warn("Ignoring IntVecDis write\n");
268        return;
269    }
270    assert(type == 0);
271    ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
272}
273
274bool
275Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
276{
277    // If we are already dealing with an interrupt for that cpu we can't deal
278    // with another one right now... come back later
279    if (jIntBusy[cpu_id].busy)
280        return false;
281
282    jIntBusy[cpu_id].busy = true;
283    jIntBusy[cpu_id].source = source;
284    jBusData0[cpu_id] = d0;
285    jBusData1[cpu_id] = d1;
286
287    ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
288    return true;
289}
290
291void
292Iob::addressRanges(AddrRangeList &range_list)
293{
294    range_list.clear();
295    range_list.push_back(RangeSize(iobManAddr, iobManSize));
296    range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize));
297}
298
299
300void
301Iob::serialize(std::ostream &os)
302{
303
304    SERIALIZE_SCALAR(jIntVec);
305    SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
306    SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
307    for (int x = 0; x < NumDeviceIds; x++) {
308        nameOut(os, csprintf("%s.Int%d", name(), x));
309        paramOut(os, "cpu", intMan[x].cpu);
310        paramOut(os, "vector", intMan[x].vector);
311        paramOut(os, "mask", intCtl[x].mask);
312        paramOut(os, "pend", intCtl[x].pend);
313    };
314    for (int x = 0; x < MaxNiagaraProcs; x++) {
315        nameOut(os, csprintf("%s.jIntBusy%d", name(), x));
316        paramOut(os, "busy", jIntBusy[x].busy);
317        paramOut(os, "source", jIntBusy[x].source);
318    };
319}
320
321void
322Iob::unserialize(Checkpoint *cp, const std::string &section)
323{
324    UNSERIALIZE_SCALAR(jIntVec);
325    UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
326    UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
327    for (int x = 0; x < NumDeviceIds; x++) {
328        paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu);
329        paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector);
330        paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask);
331        paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend);
332    };
333    for (int x = 0; x < MaxNiagaraProcs; x++) {
334        paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy);
335        paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source);
336    };
337}
338
339
340
341
342BEGIN_DECLARE_SIM_OBJECT_PARAMS(Iob)
343    Param<Tick> pio_latency;
344    SimObjectParam<Platform *> platform;
345    SimObjectParam<System *> system;
346END_DECLARE_SIM_OBJECT_PARAMS(Iob)
347
348BEGIN_INIT_SIM_OBJECT_PARAMS(Iob)
349
350    INIT_PARAM(pio_latency, "Programmed IO latency"),
351    INIT_PARAM(platform, "platform"),
352    INIT_PARAM(system, "system object")
353
354END_INIT_SIM_OBJECT_PARAMS(Iob)
355
356CREATE_SIM_OBJECT(Iob)
357{
358    Iob::Params *p = new Iob::Params;
359    p->name = getInstanceName();
360    p->pio_delay = pio_latency;
361    p->platform = platform;
362    p->system = system;
363    return new Iob(p);
364}
365
366REGISTER_SIM_OBJECT("Iob", Iob)
367