From 1694c65ba169a555bd642d3352c65be41a36ce4d Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Sat, 3 Mar 2007 19:02:31 -0500 Subject: [PATCH] Add Iob and remove the fake device configs/common/FSConfig.py: add an attachOnChipIO to force people to think about where "onchip" i/o should be connected in their hierarchy --HG-- extra : convert_revision : cf79a9a00760b7daf28063f407a04bd38b956843 --- configs/common/FSConfig.py | 1 + src/dev/sparc/iob.cc | 366 +++++++++++++++++++++++++++++++++ src/dev/sparc/iob.hh | 153 ++++++++++++++ src/python/m5/objects/T1000.py | 20 +- 4 files changed, 533 insertions(+), 7 deletions(-) create mode 100644 src/dev/sparc/iob.cc create mode 100644 src/dev/sparc/iob.hh diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index 00ce105e0..da35698f2 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -96,6 +96,7 @@ def makeSparcSystem(mem_mode, mdesc = None): self.membus = Bus(bus_id=1) self.bridge = Bridge() self.t1000 = T1000() + self.t1000.attachOnChipIO(self.membus) self.t1000.attachIO(self.iobus) self.physmem = PhysicalMemory(range = AddrRange(Addr('1MB'), size = '64MB'), zero = True) self.physmem2 = PhysicalMemory(range = AddrRange(Addr('2GB'), size ='256MB'), zero = True) diff --git a/src/dev/sparc/iob.cc b/src/dev/sparc/iob.cc new file mode 100644 index 000000000..b8caff7e9 --- /dev/null +++ b/src/dev/sparc/iob.cc @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** @file + * This device implemetns the niagara I/O bridge chip. It manages incomming + * interrupts and posts them to the CPU when needed. It holds mask registers and + * various status registers for CPUs to check what interrupts are pending as + * well as facilities to send IPIs to other cpus. + */ + +#include + +#include "arch/sparc/isa_traits.hh" +#include "base/trace.hh" +#include "cpu/intr_control.hh" +#include "dev/sparc/iob.hh" +#include "dev/platform.hh" +#include "mem/port.hh" +#include "mem/packet_access.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +Iob::Iob(Params *p) + : PioDevice(p), ic(p->platform->intrctrl) +{ + iobManAddr = ULL(0x9800000000); + iobManSize = ULL(0x0100000000); + iobJBusAddr = ULL(0x9F00000000); + iobJBusSize = ULL(0x0100000000); + assert (params()->system->threadContexts.size() <= MaxNiagaraProcs); + // Get the interrupt controller from the platform + ic = platform->intrctrl; + + for (int x = 0; x < NumDeviceIds; ++x) { + intMan[x].cpu = 0; + intMan[x].vector = 0; + intCtl[x].mask = true; + intCtl[x].pend = false; + } + +} + +Tick +Iob::read(PacketPtr pkt) +{ + assert(pkt->result == Packet::Unknown); + + if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) + readIob(pkt); + else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) + readJBus(pkt); + else + panic("Invalid address reached Iob\n"); + + pkt->result = Packet::Success; + return pioDelay; +} + +void +Iob::readIob(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobManAddr; + int index; + uint64_t data; + + if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) { + index = (accessAddr - IntManAddr) >> 3; + data = intMan[index].cpu << 8 | intMan[index].vector << 0; + pkt->set(data); + return; + } + + if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) { + index = (accessAddr - IntManAddr) >> 3; + data = intCtl[index].mask ? 1 << 2 : 0 | + intCtl[index].pend ? 1 << 0 : 0; + pkt->set(data); + return; + } + + if (accessAddr == JIntVecAddr) { + pkt->set(jIntVec); + return; + } + + panic("Read to unknown IOB offset 0x%x\n", accessAddr); +} + +void +Iob::readJBus(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobJBusAddr; + int cpuid = pkt->req->getCpuNum(); + int index; + uint64_t data; + + + + + if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) { + index = (accessAddr - JIntData0Addr) >> 3; + pkt->set(jBusData0[index]); + return; + } + + if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) { + index = (accessAddr - JIntData1Addr) >> 3; + pkt->set(jBusData1[index]); + return; + } + + if (accessAddr == JIntDataA0Addr) { + pkt->set(jBusData0[cpuid]); + return; + } + + if (accessAddr == JIntDataA1Addr) { + pkt->set(jBusData1[cpuid]); + return; + } + + if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) { + index = (accessAddr - JIntBusyAddr) >> 3; + data = jIntBusy[index].busy ? 1 << 5 : 0 | + jIntBusy[index].source; + pkt->set(data); + return; + } + if (accessAddr == JIntABusyAddr) { + data = jIntBusy[cpuid].busy ? 1 << 5 : 0 | + jIntBusy[cpuid].source; + pkt->set(data); + return; + }; + + panic("Read to unknown JBus offset 0x%x\n", accessAddr); +} + +Tick +Iob::write(PacketPtr pkt) +{ + if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) + writeIob(pkt); + else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) + writeJBus(pkt); + else + panic("Invalid address reached Iob\n"); + + + pkt->result = Packet::Success; + return pioDelay; +} + +void +Iob::writeIob(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobManAddr; + int index; + uint64_t data; + + if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) { + index = (accessAddr - IntManAddr) >> 3; + data = pkt->get(); + intMan[index].cpu = bits(data,12,8); + intMan[index].vector = bits(data,5,0); + return; + } + + if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) { + index = (accessAddr - IntManAddr) >> 3; + data = pkt->get(); + intCtl[index].mask = bits(data,2,2); + if (bits(data,1,1)) + intCtl[index].pend = false; + return; + } + + if (accessAddr == JIntVecAddr) { + jIntVec = bits(pkt->get(), 5,0); + return; + } + + if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) { + Type type; + int cpu_id; + int vector; + index = (accessAddr - IntManAddr) >> 3; + data = pkt->get(); + type = (Type)bits(data,17,16); + cpu_id = bits(data, 12,8); + vector = bits(data,5,0); + generateIpi(type,cpu_id, vector); + return; + } + + panic("Write to unknown IOB offset 0x%x\n", accessAddr); +} + +void +Iob::writeJBus(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobJBusAddr; + int cpuid = pkt->req->getCpuNum(); + int index; + uint64_t data; + + if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) { + index = (accessAddr - JIntBusyAddr) >> 3; + data = pkt->get(); + jIntBusy[index].busy = bits(data,5,5); + return; + } + if (accessAddr == JIntABusyAddr) { + data = pkt->get(); + jIntBusy[cpuid].busy = bits(data,5,5); + return; + }; + + panic("Write to unknown JBus offset 0x%x\n", accessAddr); +} + +void +Iob::receiveDeviceInterrupt(DeviceId devid) +{ + assert(devid < NumDeviceIds); + if (intCtl[devid].mask) + return; + intCtl[devid].mask = true; + intCtl[devid].pend = true; + ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector); +} + + +void +Iob::generateIpi(Type type, int cpu_id, int vector) +{ + // Only handle interrupts for the moment... Cpu Idle/reset/resume will be + // later + if (type != 0) { + warn("Ignoring IntVecDis write\n"); + return; + } + assert(type == 0); + ic->post(cpu_id, SparcISA::IT_INT_VEC, vector); +} + +bool +Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1) +{ + // If we are already dealing with an interrupt for that cpu we can't deal + // with another one right now... come back later + if (jIntBusy[cpu_id].busy) + return false; + + jIntBusy[cpu_id].busy = true; + jIntBusy[cpu_id].source = source; + jBusData0[cpu_id] = d0; + jBusData1[cpu_id] = d1; + + ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec); + return true; +} + +void +Iob::addressRanges(AddrRangeList &range_list) +{ + range_list.clear(); + range_list.push_back(RangeSize(iobManAddr, iobManSize)); + range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize)); +} + + +void +Iob::serialize(std::ostream &os) +{ + + SERIALIZE_SCALAR(jIntVec); + SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); + SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); + for (int x = 0; x < NumDeviceIds; x++) { + nameOut(os, csprintf("%s.Int%d", name(), x)); + paramOut(os, "cpu", intMan[x].cpu); + paramOut(os, "vector", intMan[x].vector); + paramOut(os, "mask", intCtl[x].mask); + paramOut(os, "pend", intCtl[x].pend); + }; + for (int x = 0; x < MaxNiagaraProcs; x++) { + nameOut(os, csprintf("%s.jIntBusy%d", name(), x)); + paramOut(os, "busy", jIntBusy[x].busy); + paramOut(os, "source", jIntBusy[x].source); + }; +} + +void +Iob::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(jIntVec); + UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); + UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); + for (int x = 0; x < NumDeviceIds; x++) { + paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu); + paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector); + paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask); + paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend); + }; + for (int x = 0; x < MaxNiagaraProcs; x++) { + paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy); + paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source); + }; +} + + + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Iob) + Param pio_latency; + SimObjectParam platform; + SimObjectParam system; +END_DECLARE_SIM_OBJECT_PARAMS(Iob) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Iob) + + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object") + +END_INIT_SIM_OBJECT_PARAMS(Iob) + +CREATE_SIM_OBJECT(Iob) +{ + Iob::Params *p = new Iob::Params; + p->name = getInstanceName(); + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + return new Iob(p); +} + +REGISTER_SIM_OBJECT("Iob", Iob) diff --git a/src/dev/sparc/iob.hh b/src/dev/sparc/iob.hh new file mode 100644 index 000000000..c05c4f2ef --- /dev/null +++ b/src/dev/sparc/iob.hh @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** @file + * This device implements the niagara I/O Bridge chip. The device manages + * internal (ipi) and external (serial, pci via jbus). + */ + +#ifndef __DEV_SPARC_IOB_HH__ +#define __DEV_SPARC_IOB_HH__ + +#include "base/range.hh" +#include "dev/io_device.hh" +#include "dev/disk_image.hh" + +class IntrControl; + +const int MaxNiagaraProcs = 32; +// IOB Managment Addresses +const Addr IntManAddr = 0x0000; +const Addr IntManSize = 0x0020; +const Addr IntCtlAddr = 0x0400; +const Addr IntCtlSize = 0x0020; +const Addr JIntVecAddr = 0x0A00; +const Addr IntVecDisAddr = 0x0800; +const Addr IntVecDisSize = 0x0100; + + +// IOB Control Addresses +const Addr JIntData0Addr = 0x0400; +const Addr JIntData1Addr = 0x0500; +const Addr JIntDataA0Addr = 0x0600; +const Addr JIntDataA1Addr = 0x0700; +const Addr JIntBusyAddr = 0x0900; +const Addr JIntBusySize = 0x0100; +const Addr JIntABusyAddr = 0x0B00; + + +// IOB Masks +const uint64_t IntManMask = 0x01F3F; +const uint64_t IntCtlMask = 0x00006; +const uint64_t JIntVecMask = 0x0003F; +const uint64_t IntVecDis = 0x31F3F; +const uint64_t JIntBusyMask = 0x0003F; + + +class Iob : public PioDevice +{ + private: + IntrControl *ic; + Addr iobManAddr; + Addr iobManSize; + Addr iobJBusAddr; + Addr iobJBusSize; + Tick pioDelay; + + enum DeviceId { + Interal = 0, + Error = 1, + SSI = 2, + Reserved = 3, + NumDeviceIds + }; + + struct IntMan { + int cpu; + int vector; + }; + + struct IntCtl { + bool mask; + bool pend; + }; + + struct IntBusy { + bool busy; + int source; + }; + + enum Type { + Interrupt, + Reset, + Idle, + Resume + }; + + IntMan intMan[NumDeviceIds]; + IntCtl intCtl[NumDeviceIds]; + uint64_t jIntVec; + uint64_t jBusData0[MaxNiagaraProcs]; + uint64_t jBusData1[MaxNiagaraProcs]; + IntBusy jIntBusy[MaxNiagaraProcs]; + + void writeIob(PacketPtr pkt); + void writeJBus(PacketPtr pkt); + void readIob(PacketPtr pkt); + void readJBus(PacketPtr pkt); + + + public: + struct Params : public PioDevice::Params + { + Tick pio_delay; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + Iob(Params *p); + + virtual Tick read(PacketPtr pkt); + virtual Tick write(PacketPtr pkt); + void generateIpi(Type type, int cpu_id, int vector); + void receiveDeviceInterrupt(DeviceId devid); + bool receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1); + + + void addressRanges(AddrRangeList &range_list); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif //__DEV_SPARC_IOB_HH__ + diff --git a/src/python/m5/objects/T1000.py b/src/python/m5/objects/T1000.py index aeca491c4..0acfa0920 100644 --- a/src/python/m5/objects/T1000.py +++ b/src/python/m5/objects/T1000.py @@ -1,6 +1,6 @@ from m5.params import * from m5.proxy import * -from Device import BasicPioDevice, IsaFake, BadAddr +from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr from Uart import Uart8250 from Platform import Platform from SimConsole import SimConsole @@ -16,6 +16,10 @@ class DumbTOD(BasicPioDevice): time = Param.Time('01/01/2009', "System time to use ('Now' for real time)") pio_addr = 0xfff0c1fff8 +class Iob(PioDevice): + type = 'Iob' + pio_latency = Param.Latency('1ns', "Programed IO latency in simticks") + class T1000(Platform): type = 'T1000' @@ -28,9 +32,6 @@ class T1000(Platform): ret_data64=0x0000000000000000, update_data=False) #warn_access="Accessing Memory Banks -- Unimplemented!") - fake_iob = IsaFake(pio_addr=0x9800000000, pio_size=0x100000000) - #warn_access="Accessing IOB -- Unimplemented!") - fake_jbi = IsaFake(pio_addr=0x8000000000, pio_size=0x100000000) #warn_access="Accessing JBI -- Unimplemented!") @@ -76,6 +77,13 @@ class T1000(Platform): pconsole = SimConsole() puart0 = Uart8250(pio_addr=0x1f10000000) + iob = Iob() + # Attach I/O devices that are on chip + def attachOnChipIO(self, bus): + self.iob.pio = bus.port + self.htod.pio = bus.port + + # Attach I/O devices to specified bus object. Can't do this # earlier, since the bus object itself is typically defined at the # System level. @@ -84,8 +92,6 @@ class T1000(Platform): self.puart0.sim_console = self.pconsole self.fake_clk.pio = bus.port self.fake_membnks.pio = bus.port - self.fake_iob.pio = bus.port - self.fake_jbi.pio = bus.port self.fake_l2_1.pio = bus.port self.fake_l2_2.pio = bus.port self.fake_l2_3.pio = bus.port @@ -95,6 +101,6 @@ class T1000(Platform): self.fake_l2esr_3.pio = bus.port self.fake_l2esr_4.pio = bus.port self.fake_ssi.pio = bus.port + self.fake_jbi.pio = bus.port self.puart0.pio = bus.port self.hvuart.pio = bus.port - self.htod.pio = bus.port