X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=dev%2Ftsunami_cchip.cc;h=2fb293fbf70feccec4c84c89ea543447ea38b8a1;hb=91601f44948060939527bad44e82b1379168fc6c;hp=b825a91bc68efa1d72b508caac57b54312cab581;hpb=e72e8b28c8579f56b36b89f1b6cbfba169202f1e;p=gem5.git diff --git a/dev/tsunami_cchip.cc b/dev/tsunami_cchip.cc index b825a91bc..2fb293fbf 100644 --- a/dev/tsunami_cchip.cc +++ b/dev/tsunami_cchip.cc @@ -1,4 +1,30 @@ -/* $Id$ */ +/* + * Copyright (c) 2004 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. + */ /* @file * Emulation of the Tsunami CChip CSRs @@ -9,33 +35,42 @@ #include #include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "dev/console.hh" #include "dev/tsunami_cchip.hh" #include "dev/tsunamireg.h" #include "dev/tsunami.hh" -#include "cpu/intr_control.hh" +#include "mem/bus/bus.hh" +#include "mem/bus/pio_interface.hh" +#include "mem/bus/pio_interface_impl.hh" #include "mem/functional_mem/memory_control.hh" +#include "cpu/intr_control.hh" #include "sim/builder.hh" #include "sim/system.hh" using namespace std; TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a, - MemoryController *mmu) - : FunctionalMemory(name), addr(a), tsunami(t) + MemoryController *mmu, HierParams *hier, Bus* bus, + Tick pio_latency) + : PioDevice(name, t), addr(a), tsunami(t) { - mmu->add_child(this, Range(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); - for(int i=0; i < Tsunami::Max_CPUs; i++) { - dim[i] = 0; - dir[i] = 0; - dirInterrupting[i] = false; + if (bus) { + pioInterface = newPioInterface(name, hier, bus, this, + &TsunamiCChip::cacheAccess); + pioInterface->addAddrRange(RangeSize(addr, size)); + pioLatency = pio_latency * bus->clockRatio; } drir = 0; - misc = 0; - RTCInterrupting = false; + ipint = 0; + itint = 0; + + for (int x = 0; x < Tsunami::Max_CPUs; x++) + { + dim[x] = 0; + dir[x] = 0; + } //Put back pointer in tsunami tsunami->cchip = this; @@ -44,16 +79,29 @@ TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a, Fault TsunamiCChip::read(MemReqPtr &req, uint8_t *data) { - DPRINTF(Tsunami, "read va=%#x size=%d\n", - req->vaddr, req->size); + DPRINTF(Tsunami, "read va=%#x size=%d\n", req->vaddr, req->size); + + Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6; ExecContext *xc = req->xc; switch (req->size) { case sizeof(uint64_t): - switch(daddr) { + if (daddr & TSDEV_CC_BDIMS) + { + *(uint64_t*)data = dim[(daddr >> 4) & 0x3F]; + return No_Fault; + } + + if (daddr & TSDEV_CC_BDIRS) + { + *(uint64_t*)data = dir[(daddr >> 4) & 0x3F]; + return No_Fault; + } + + switch(regnum) { case TSDEV_CC_CSR: *(uint64_t*)data = 0x0; return No_Fault; @@ -61,13 +109,15 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data) panic("TSDEV_CC_MTR not implemeted\n"); return No_Fault; case TSDEV_CC_MISC: - *(uint64_t*)data = misc | (xc->cpu_id & 0x3); + *(uint64_t*)data = (ipint << 8) & 0xF | + (itint << 4) & 0xF | + (xc->cpu_id & 0x3); return No_Fault; case TSDEV_CC_AAR0: case TSDEV_CC_AAR1: case TSDEV_CC_AAR2: case TSDEV_CC_AAR3: - panic("TSDEV_CC_AARx not implemeted\n"); + *(uint64_t*)data = 0; return No_Fault; case TSDEV_CC_DIM0: *(uint64_t*)data = dim[0]; @@ -111,18 +161,31 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data) case TSDEV_CC_MPR3: panic("TSDEV_CC_MPRx not implemented\n"); return No_Fault; + case TSDEV_CC_IPIR: + *(uint64_t*)data = ipint; + return No_Fault; + case TSDEV_CC_ITIR: + *(uint64_t*)data = itint; + return No_Fault; default: panic("default in cchip read reached, accessing 0x%x\n"); } // uint64_t break; case sizeof(uint32_t): + if (regnum == TSDEV_CC_DRIR) { + warn("accessing DRIR with 32 bit read, " + "hopefully your just reading this for timing"); + *(uint32_t*)data = drir; + } else + panic("invalid access size(?) for tsunami register!\n"); + return No_Fault; case sizeof(uint16_t): case sizeof(uint8_t): default: panic("invalid access size(?) for tsunami register!\n"); } - DPRINTFN("Tsunami CChip ERROR: read daddr=%#x size=%d\n", daddr, req->size); + DPRINTFN("Tsunami CChip ERROR: read regnum=%#x size=%d\n", regnum, req->size); return No_Fault; } @@ -130,15 +193,60 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data) Fault TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) { - DPRINTF(Tsunami, "write - va=%#x size=%d \n", - req->vaddr, req->size); + DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n", + req->vaddr, *(uint64_t*)data, req->size); + + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); + Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6; + bool supportedWrite = false; switch (req->size) { case sizeof(uint64_t): - switch(daddr) { + if (daddr & TSDEV_CC_BDIMS) + { + int number = (daddr >> 4) & 0x3F; + + uint64_t bitvector; + uint64_t olddim; + uint64_t olddir; + + olddim = dim[number]; + olddir = dir[number]; + dim[number] = *(uint64_t*)data; + dir[number] = dim[number] & drir; + for(int x = 0; x < Tsunami::Max_CPUs; x++) + { + bitvector = ULL(1) << x; + // Figure out which bits have changed + if ((dim[number] & bitvector) != (olddim & bitvector)) + { + // The bit is now set and it wasn't before (set) + if((dim[number] & bitvector) && (dir[number] & bitvector)) + { + tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in posting dir" + " interrupt to cpu %d\n", number); + } + else if ((olddir & bitvector) && + !(dir[number] & bitvector)) + { + // The bit was set and now its now clear and + // we were interrupting on that bit before + tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in clear" + " dir interrupt to cpu %d\n", number); + + } + + + } + } + return No_Fault; + } + + switch(regnum) { case TSDEV_CC_CSR: panic("TSDEV_CC_CSR write\n"); return No_Fault; @@ -146,14 +254,38 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) panic("TSDEV_CC_MTR write not implemented\n"); return No_Fault; case TSDEV_CC_MISC: - //If it is the seventh bit, clear the RTC interrupt - if ((*(uint64_t*) data) & (1<<4)) { - RTCInterrupting = false; - tsunami->intrctrl->clear(0, TheISA::INTLEVEL_IRQ2, 0); - DPRINTF(Tsunami, "clearing rtc interrupt\n"); - misc &= ~(1<<4); - } else panic("TSDEV_CC_MISC write not implemented\n"); - return No_Fault; + uint64_t ipreq; + ipreq = (*(uint64_t*)data >> 12) & 0xF; + //If it is bit 12-15, this is an IPI post + if (ipreq) { + reqIPI(ipreq); + supportedWrite = true; + } + + //If it is bit 8-11, this is an IPI clear + uint64_t ipintr; + ipintr = (*(uint64_t*)data >> 8) & 0xF; + if (ipintr) { + clearIPI(ipintr); + supportedWrite = true; + } + + //If it is the 4-7th bit, clear the RTC interrupt + uint64_t itintr; + itintr = (*(uint64_t*)data >> 4) & 0xF; + if (itintr) { + clearITI(itintr); + supportedWrite = true; + } + + // ignore NXMs + if (*(uint64_t*)data & 0x10000000) + supportedWrite = true; + + if(!supportedWrite) + panic("TSDEV_CC_MISC write not implemented\n"); + + return No_Fault; case TSDEV_CC_AAR0: case TSDEV_CC_AAR1: case TSDEV_CC_AAR2: @@ -161,47 +293,53 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) panic("TSDEV_CC_AARx write not implemeted\n"); return No_Fault; case TSDEV_CC_DIM0: - dim[0] = *(uint64_t*)data; - if (dim[0] & drir) { - dir[0] = dim[0] & drir; - if (!dirInterrupting[0]) { - dirInterrupting[0] = true; - tsunami->intrctrl->post(0, TheISA::INTLEVEL_IRQ1, 0); - DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n"); - } - } - return No_Fault; case TSDEV_CC_DIM1: - dim[1] = *(uint64_t*)data; - if (dim[1] & drir) { - dir[1] = dim[1] & drir; - if (!dirInterrupting[1]) { - dirInterrupting[1] = true; - tsunami->intrctrl->post(1, TheISA::INTLEVEL_IRQ1, 0); - DPRINTF(Tsunami, "posting dir interrupt to cpu 1\n"); - } - } - return No_Fault; case TSDEV_CC_DIM2: - dim[2] = *(uint64_t*)data; - if (dim[2] & drir) { - dir[2] = dim[2] & drir; - if (!dirInterrupting[2]) { - dirInterrupting[2] = true; - tsunami->intrctrl->post(2, TheISA::INTLEVEL_IRQ1, 0); - DPRINTF(Tsunami, "posting dir interrupt to cpu 2\n"); - } - } - return No_Fault; case TSDEV_CC_DIM3: - dim[3] = *(uint64_t*)data; - if ((dim[3] & drir) /*And Not Already Int*/) { - dir[3] = dim[3] & drir; - if (!dirInterrupting[3]) { - dirInterrupting[3] = true; - tsunami->intrctrl->post(3, TheISA::INTLEVEL_IRQ1, 0); - DPRINTF(Tsunami, "posting dir interrupt to cpu 3\n"); - } + int number; + if(regnum == TSDEV_CC_DIM0) + number = 0; + else if(regnum == TSDEV_CC_DIM1) + number = 1; + else if(regnum == TSDEV_CC_DIM2) + number = 2; + else + number = 3; + + uint64_t bitvector; + uint64_t olddim; + uint64_t olddir; + + olddim = dim[number]; + olddir = dir[number]; + dim[number] = *(uint64_t*)data; + dir[number] = dim[number] & drir; + for(int x = 0; x < 64; x++) + { + bitvector = ULL(1) << x; + // Figure out which bits have changed + if ((dim[number] & bitvector) != (olddim & bitvector)) + { + // The bit is now set and it wasn't before (set) + if((dim[number] & bitvector) && (dir[number] & bitvector)) + { + tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n"); + } + else if ((olddir & bitvector) && + !(dir[number] & bitvector)) + { + // The bit was set and now its now clear and + // we were interrupting on that bit before + tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in clear" + " dir interrupt to cpu %d\n", + x); + + } + + + } } return No_Fault; case TSDEV_CC_DIR0: @@ -209,24 +347,28 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) case TSDEV_CC_DIR2: case TSDEV_CC_DIR3: panic("TSDEV_CC_DIR write not implemented\n"); - return No_Fault; case TSDEV_CC_DRIR: panic("TSDEV_CC_DRIR write not implemented\n"); - return No_Fault; case TSDEV_CC_PRBEN: panic("TSDEV_CC_PRBEN write not implemented\n"); - return No_Fault; case TSDEV_CC_IIC0: case TSDEV_CC_IIC1: case TSDEV_CC_IIC2: case TSDEV_CC_IIC3: panic("TSDEV_CC_IICx write not implemented\n"); - return No_Fault; case TSDEV_CC_MPR0: case TSDEV_CC_MPR1: case TSDEV_CC_MPR2: case TSDEV_CC_MPR3: panic("TSDEV_CC_MPRx write not implemented\n"); + case TSDEV_CC_IPIR: + clearIPI(*(uint64_t*)data); + return No_Fault; + case TSDEV_CC_ITIR: + clearITI(*(uint64_t*)data); + return No_Fault; + case TSDEV_CC_IPIQ: + reqIPI(*(uint64_t*)data); return No_Fault; default: panic("default in cchip read reached, accessing 0x%x\n"); @@ -246,46 +388,162 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) } void -TsunamiCChip::postDRIR(uint64_t bitvector) +TsunamiCChip::clearIPI(uint64_t ipintr) { - drir |= bitvector; - for(int i=0; i < Tsunami::Max_CPUs; i++) { - if (bitvector & dim[i]) { - dir[i] |= bitvector; - if (!dirInterrupting[i]) { - dirInterrupting[i] = true; - tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, 0); - DPRINTF(Tsunami, "posting dir interrupt to cpu %d\n",i); + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipintr) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipintr & cpumask) { + // Check if there is a pending ipi + if (ipint & cpumask) { + ipint &= ~cpumask; + tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum); + } + else + warn("clear IPI for CPU=%d, but NO IPI\n", cpunum); + } + } + } + else + panic("Big IPI Clear, but not processors indicated\n"); +} + +void +TsunamiCChip::clearITI(uint64_t itintr) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (itintr) { + for (int i=0; i < numcpus; i++) { + uint64_t cpumask = ULL(1) << i; + if (itintr & cpumask & itint) { + tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0); + itint &= ~cpumask; + DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i); } } } + else + panic("Big ITI Clear, but not processors indicated\n"); } void -TsunamiCChip::clearDRIR(uint64_t bitvector) +TsunamiCChip::reqIPI(uint64_t ipreq) { - drir &= ~bitvector; - for(int i=0; i < Tsunami::Max_CPUs; i++) { - dir[i] &= ~bitvector; - if (!dir[i]) { - dirInterrupting[i] = false; - tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, 0); - DPRINTF(Tsunami, "clearing dir interrupt to cpu %d\n", i); + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipreq) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipreq & cpumask) { + // Check if there is already an ipi (bits 8:11) + if (!(ipint & cpumask)) { + ipint |= cpumask; + tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "send IPI cpu=%d\n", cpunum); + } + else + warn("post IPI for CPU=%d, but IPI already\n", cpunum); + } + } + } + else + panic("Big IPI Request, but not processors indicated\n"); +} + +void +TsunamiCChip::postRTC() +{ + int size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + + for (int i = 0; i < size; i++) { + uint64_t cpumask = ULL(1) << i; + if (!(cpumask & itint)) { + itint |= cpumask; + tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0); + DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i); } } + } +void +TsunamiCChip::postDRIR(uint32_t interrupt) +{ + uint64_t bitvector = ULL(1) << interrupt; + uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + drir |= bitvector; + + for(int i=0; i < size; i++) { + dir[i] = dim[i] & drir; + if (dim[i] & bitvector) { + tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt); + DPRINTF(Tsunami, "posting dir interrupt to cpu %d," + "interrupt %d\n",i, interrupt); + } + } +} + +void +TsunamiCChip::clearDRIR(uint32_t interrupt) +{ + uint64_t bitvector = ULL(1) << interrupt; + uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + + if (drir & bitvector) + { + drir &= ~bitvector; + for(int i=0; i < size; i++) { + if (dir[i] & bitvector) { + tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt); + DPRINTF(Tsunami, "clearing dir interrupt to cpu %d," + "interrupt %d\n",i, interrupt); + + } + dir[i] = dim[i] & drir; + } + } + else + DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt); +} + +Tick +TsunamiCChip::cacheAccess(MemReqPtr &req) +{ + return curTick + pioLatency; +} + + void TsunamiCChip::serialize(std::ostream &os) { - // code should be written + SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); + SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); + SERIALIZE_SCALAR(ipint); + SERIALIZE_SCALAR(itint); + SERIALIZE_SCALAR(drir); } void TsunamiCChip::unserialize(Checkpoint *cp, const std::string §ion) { - //code should be written + UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); + UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); + UNSERIALIZE_SCALAR(ipint); + UNSERIALIZE_SCALAR(itint); + UNSERIALIZE_SCALAR(drir); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) @@ -293,6 +551,9 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) SimObjectParam tsunami; SimObjectParam mmu; Param addr; + SimObjectParam io_bus; + Param pio_latency; + SimObjectParam hier; END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) @@ -300,13 +561,17 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) INIT_PARAM(tsunami, "Tsunami"), INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address") + INIT_PARAM(addr, "Device Address"), + INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), + INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) CREATE_SIM_OBJECT(TsunamiCChip) { - return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu); + return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu, hier, + io_bus, pio_latency); } REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)