diff --git a/CMakeLists.txt b/CMakeLists.txt index db7feb9..31ceb51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,6 +105,8 @@ add_executable(axe Token.h SSwitch.h SSwitch.cpp + SSwitchCtrlRegs.h + SSwitchCtrlRegs.cpp WaveformTracer.h WaveformTracer.cpp UartRx.h diff --git a/Chanend.cpp b/Chanend.cpp index 2f99b94..681e742 100644 --- a/Chanend.cpp +++ b/Chanend.cpp @@ -71,6 +71,7 @@ bool Chanend::openRoute() { if (inPacket) return true; + dest = getOwner().getParent().getChanendDest(destID); if (!dest) { // TODO if dest in unset should give a link error exception. junkPacket = true; @@ -86,11 +87,11 @@ bool Chanend::setData(Thread &thread, uint32_t value, ticks_t time) updateOwner(thread); if (inPacket) return false; - ResourceID destID(value); - if (destID.type() != RES_TYPE_CHANEND && - destID.type() != RES_TYPE_CONFIG) + ResourceID id(value); + if (id.type() != RES_TYPE_CHANEND && + id.type() != RES_TYPE_CONFIG) return false; - dest = thread.getParent().getChanendDest(destID); + destID = value; return true; } @@ -159,6 +160,7 @@ outct(Thread &thread, uint8_t value, ticks_t time) dest->receiveCtrlToken(time, value); if (value == CT_END || value == CT_PAUSE) { inPacket = false; + dest = 0; } return CONTINUE; } diff --git a/Chanend.h b/Chanend.h index e02cbab..746c1e9 100644 --- a/Chanend.h +++ b/Chanend.h @@ -13,7 +13,10 @@ class Chanend : public EventableResource, public ChanEndpoint { private: - /// The destination channel end. + // The destination resource ID. + uint32_t destID; + /// The destination channel end. Only valid when in the the middle of a + /// packet. ChanEndpoint *dest; /// Input buffer. typedef ring_buffer TokenBuffer; diff --git a/ConfigSchema.rng b/ConfigSchema.rng index 0c55228..ef7117e 100644 --- a/ConfigSchema.rng +++ b/ConfigSchema.rng @@ -11,12 +11,14 @@ + Nodes + Connections JtagChain @@ -48,6 +50,45 @@ + + + + + + + + + + + + SLink + + + + + + + + + + + + + + + + + + end1 + end2 + + + + + + + + @@ -82,12 +123,14 @@ - + + Processor + Switch @@ -133,25 +176,37 @@ - - - - + + + + + + + + + + sLinks + + + + + - + - - - - - - - + + + + + + + + @@ -160,6 +215,11 @@ + + + + + ([0-9]+|0x[0-9a-fA-F]+|0[0-8]+) diff --git a/Core.cpp b/Core.cpp index 0142d1a..e77046d 100644 --- a/Core.cpp +++ b/Core.cpp @@ -258,22 +258,26 @@ initCache(OPCODE_TYPE decode, OPCODE_TYPE illegalPC, decodeOpcode = decode; } +void Core::resetCaches() +{ + uint32_t ramEnd = ram_base + (1 << ramSizeLog2); + for (unsigned address = ram_base; address < ramEnd; address += 4) { + invalidateWord(address); + } +} + bool Core::getLocalChanendDest(ResourceID ID, ChanEndpoint *&result) { assert(ID.isChanendOrConfig()); if (ID.isConfig()) { switch (ID.num()) { - case RES_CONFIG_SSCTRL: - if (parent->hasMatchingNodeID(ID)) { - result = parent->getSSwitch(); - return true; - } - break; - case RES_CONFIG_PSCTRL: - // TODO. - assert(0); - result = 0; - return true; + case RES_CONFIG_SSCTRL: + return false; + case RES_CONFIG_PSCTRL: + // TODO. + assert(0); + result = 0; + return true; } } else { if (ID.node() == getCoreID()) { @@ -298,7 +302,7 @@ ChanEndpoint *Core::getChanendDest(ResourceID ID) // Try to lookup locally first. if (getLocalChanendDest(ID, result)) return result; - return parent->getParent()->getChanendDest(ID); + return parent->getChanendDest(ID); } void Core::finalize() diff --git a/Core.h b/Core.h index fd59cab..432d416 100644 --- a/Core.h +++ b/Core.h @@ -111,6 +111,8 @@ class Core { OPCODE_TYPE illegalPCThread, OPCODE_TYPE runJit, OPCODE_TYPE interpretOne); + void resetCaches(); + void runJIT(uint32_t jitPc); uint32_t getRamSize() const { return 1 << ramSizeLog2; } diff --git a/Node.cpp b/Node.cpp index f669fad..91af874 100644 --- a/Node.cpp +++ b/Node.cpp @@ -6,6 +6,48 @@ #include "Node.h" #include "Core.h" +XLink::XLink() : + destNode(0), + destXLinkNum(0), + enabled(false), + fiveWire(false), + network(0), + direction(0), + // TODO find out defaults. + interTokenDelay(0), + interSymbolDelay(0) +{ + +} + +const XLink *XLink::getDestXLink() const +{ + if (!destNode) + return 0; + return &destNode->getXLink(destXLinkNum); +} + +bool XLink::isConnected() const +{ + if (!isEnabled()) + return false; + const XLink *otherEnd = getDestXLink(); + if (!otherEnd || !otherEnd->isEnabled()) + return false; + return isFiveWire() == otherEnd->isFiveWire(); +} + +Node::Node(Type t, unsigned numXLinks) : + jtagIndex(0), + nodeID(0), + parent(0), + type(t), + sswitch(this), + coreNumberBits(0) +{ + xLinks.resize(numXLinks); +} + Node::~Node() { for (std::vector::iterator it = cores.begin(), e = cores.end(); @@ -16,11 +58,19 @@ Node::~Node() void Node::finalize() { + computeCoreNumberBits(); + directions.resize(getNodeNumberBits()); + if (type == XS1_G) { + for (unsigned i = 0, e = directions.size(); i != e; ++i) { + directions[i] = i; + } + } for (std::vector::iterator it = cores.begin(), e = cores.end(); it != e; ++it) { (*it)->updateIDs(); (*it)->finalize(); } + sswitch.initRegisters(); } void Node::addCore(std::auto_ptr c) @@ -49,12 +99,22 @@ static unsigned getMinimumBits(unsigned values) return 32 - countLeadingZeros(values - 1); } +void Node::computeCoreNumberBits() +{ + coreNumberBits = getMinimumBits(cores.size()); + if (getType() == Node::XS1_G && coreNumberBits < 8) + coreNumberBits = 8; +} + + unsigned Node::getCoreNumberBits() const { - unsigned bits = getMinimumBits(cores.size()); - if (getType() == Node::XS1_G && bits < 8) - bits = 8; - return bits; + return coreNumberBits; +} + +unsigned Node::getNodeNumberBits() const +{ + return 16 - coreNumberBits; } uint32_t Node::getCoreID(unsigned coreNum) const @@ -88,3 +148,59 @@ bool Node::hasMatchingNodeID(ResourceID ID) return ID.node() == nodeID; } } + +void Node::connectXLink(unsigned num, Node *destNode, unsigned destNum) +{ + xLinks[num].destNode = destNode; + xLinks[num].destXLinkNum = destNum; +} + +XLink *Node::getXLinkForDirection(unsigned direction) +{ + for (unsigned i = 0, e = xLinks.size(); i != e; ++i) { + XLink &xLink = xLinks[i]; + if (xLink.isEnabled() && xLinks[i].getDirection() == direction) + return &xLink; + } + return 0; +} + +ChanEndpoint *Node::getChanendDest(ResourceID ID) +{ + Node *node = this; + // Use Brent's algorithm to detect cycles. + Node *tortoise = node; + unsigned hops = 0; + unsigned leapCount = 8; + while (1) { + unsigned destNode = ID.node() >> node->getCoreNumberBits(); + unsigned diff = destNode ^ node->getNodeID(); + if (diff == 0) + break; + // Lookup direction + unsigned bit = countLeadingZeros(diff) + getNodeNumberBits() - 32; + unsigned direction = directions[bit]; + // Lookup Xlink. + XLink *xLink = getXLinkForDirection(direction); + if (!xLink || !xLink->isConnected()) + return 0; + node = xLink->destNode; + ++hops; + // Junk message if a cycle is detected. + if (node == tortoise) + return 0; + if (hops == leapCount) { + leapCount <<= 1; + tortoise = node; + } + } + if (ID.isConfig() && ID.num() == RES_CONFIG_SSCTRL) { + return &node->sswitch; + } + unsigned destCore = ID.node() & makeMask(node->getCoreNumberBits()); + if (destCore >= node->cores.size()) + return 0; + ChanEndpoint *dest = 0; + node->getCores()[destCore]->getLocalChanendDest(ID, dest); + return dest; +} diff --git a/Node.h b/Node.h index 7f2162a..12527f6 100644 --- a/Node.h +++ b/Node.h @@ -15,6 +15,36 @@ class Core; class SystemState; +class Node; + +class XLink { + friend class Node; + Node *destNode; + unsigned destXLinkNum; + bool enabled; + bool fiveWire; + uint8_t network; + uint8_t direction; + uint16_t interTokenDelay; + uint16_t interSymbolDelay; +public: + XLink(); + const XLink *getDestXLink() const; + void setEnabled(bool value) { enabled = value; } + bool isEnabled() const { return enabled; } + void setFiveWire(bool value) { fiveWire = value; } + bool isFiveWire() const { return fiveWire; } + void setNetwork(uint8_t value) { network = value; } + uint8_t getNetwork() const { return network; } + void setDirection(uint8_t value) { direction = value; } + uint8_t getDirection() const { return network; } + void setInterTokenDelay(uint16_t value) { interTokenDelay = value; } + uint16_t getInterTokenDelay() const { return interTokenDelay; } + void setInterSymbolDelay(uint16_t value) { interSymbolDelay = value; } + uint16_t getInterSymbolDelay() const { return interSymbolDelay; } + bool isConnected() const; +}; + class Node { public: enum Type { @@ -23,17 +53,24 @@ class Node { }; private: std::vector cores; + std::vector xLinks; + std::vector directions; unsigned jtagIndex; unsigned nodeID; SystemState *parent; Type type; SSwitch sswitch; + unsigned coreNumberBits; + + void computeCoreNumberBits(); unsigned getCoreNumberBits() const; + XLink *getXLinkForDirection(unsigned direction); public: typedef std::vector::iterator core_iterator; typedef std::vector::const_iterator const_core_iterator; - Node(Type t) : jtagIndex(0), nodeID(0), parent(0), type(t), sswitch(this) {} + Node(Type t, unsigned numXLinks); ~Node(); + unsigned getNodeNumberBits() const; void finalize(); void addCore(std::auto_ptr cores); void setJtagIndex(unsigned value) { jtagIndex = value; } @@ -53,6 +90,13 @@ class Node { core_iterator core_end() { return cores.end(); } const_core_iterator core_begin() const { return cores.begin(); } const_core_iterator core_end() const { return cores.end(); } + unsigned getNumXLinks() const { return xLinks.size(); } + XLink &getXLink(unsigned num) { return xLinks[num]; } + const XLink &getXLink(unsigned num) const { return xLinks[num]; } + void connectXLink(unsigned num, Node *destNode, unsigned destNum); + ChanEndpoint *getChanendDest(ResourceID ID); + uint8_t getDirection(unsigned num) const { return directions[num]; } + void setDirection(unsigned num, uint8_t value) { directions[num] = value; } }; #endif // _Node_h_ diff --git a/SSwitch.cpp b/SSwitch.cpp index ad91420..0c20ff8 100644 --- a/SSwitch.cpp +++ b/SSwitch.cpp @@ -10,31 +10,9 @@ #include "Trace.h" #include -SSwitchCtrlRegs::SSwitchCtrlRegs() : scratchReg(0) -{ - -} - -bool SSwitchCtrlRegs::read(uint16_t num, uint32_t &result) -{ - if (num != 3) { - return false; - } - result = scratchReg; - return true; -} - -bool SSwitchCtrlRegs::write(uint16_t num, uint32_t value) -{ - if (num != 3) { - return false; - } - scratchReg = value; - return true; -} - SSwitch::SSwitch(Node *p) : parent(p), + regs(p), recievedTokens(0), junkIncomingTokens(0), sendingResponse(false), @@ -131,7 +109,7 @@ void SSwitch::handleRequest(ticks_t time, const Request &request) Tracer::get().SSwitchNack(*parent, destID); } } - ChanEndpoint *dest = parent->getParent()->getChanendDest(destID); + ChanEndpoint *dest = parent->getChanendDest(destID); if (!dest) return; bool junkPacket = false; diff --git a/SSwitch.h b/SSwitch.h index 88d9125..1db080c 100644 --- a/SSwitch.h +++ b/SSwitch.h @@ -8,18 +8,10 @@ #include "Token.h" #include "ChanEndpoint.h" +#include "SSwitchCtrlRegs.h" class Node; -class SSwitchCtrlRegs { -private: - uint32_t scratchReg; -public: - SSwitchCtrlRegs(); - bool read(uint16_t num, uint32_t &result); - bool write(uint16_t num, uint32_t value); -}; - class SSwitch : public ChanEndpoint { private: struct Request { @@ -48,6 +40,7 @@ class SSwitch : public ChanEndpoint { void handleRequest(ticks_t time, const Request &request); public: SSwitch(Node *parent); + void initRegisters() { regs.initRegisters(); } virtual void notifyDestClaimed(ticks_t time); virtual void notifyDestCanAcceptTokens(ticks_t time, unsigned tokens); diff --git a/SSwitchCtrlRegs.cpp b/SSwitchCtrlRegs.cpp new file mode 100644 index 0000000..a855626 --- /dev/null +++ b/SSwitchCtrlRegs.cpp @@ -0,0 +1,239 @@ +// Copyright (c) 2011-2012, Richard Osborne, All rights reserved +// This software is freely distributable under a derivative of the +// University of Illinois/NCSA Open Source License posted in +// LICENSE.txt and at + +#include "SSwitchCtrlRegs.h" +#include "Node.h" +#include "BitManip.h" +#include + +namespace SSwitchReg { + enum { + DEVICE_ID0 = 0x0, + DEVICE_ID1 = 0x1, + DEVICE_ID2 = 0x2, + DEVICE_ID3 = 0x3, + NODE_CONFIG = 0x4, + NODE_ID = 0x5, + PLL_CTL = 0x6, + CLK_DIVIDER = 0x7, + REF_CLK_DIVIDER = 0x8, + DIMENSION_DIRECTION_0 = 0xc, + DIMENSION_DIRECTION_1 = 0xd, + XCORE0_GLOBAL_DEBUG_CONFIG = 0x10, + GLOBAL_DEBUG_SOURCE = 0x1f, + SLINK_0 = 0x20, // 8 slinks + PLINK_0 = 0x40, // 4 plinks + XLINK_0 = 0x80, // 8 xlinks + XSTATIC_0 = 0xa0, // 8 + }; +}; + +SSwitchCtrlRegs::SSwitchCtrlRegs(Node *n) : + node(n), + scratchReg(0) +{ +} + +void SSwitchCtrlRegs::initReg(unsigned num, uint8_t flags) +{ + regFlags[num] = flags; +} + +void SSwitchCtrlRegs::initRegisters() +{ + using namespace SSwitchReg; + // There is a limit to how many links can be addressed via registers. + unsigned numXLinks = std::min(node->getNumXLinks(), + (unsigned)PLINK_0 - SLINK_0); + unsigned numRegs = XSTATIC_0 + node->getNumXLinks(); + regFlags.resize(numRegs); + + initReg(NODE_ID, REG_RW); + if (node->getType() == Node::XS1_G) { + initReg(DEVICE_ID3, REG_RW); + } + unsigned numDirectionRegisters = (node->getNodeNumberBits() + 7) / 8; + if (node->getType() != Node::XS1_G) { + for (unsigned i = 0; i < numDirectionRegisters; i++) { + initReg(DIMENSION_DIRECTION_0 + i, REG_RW); + } + } + for (unsigned i = 0; i < numXLinks; i++) { + initReg(SLINK_0 + i, REG_RW); + initReg(XLINK_0 + i, REG_RW); + //initReg(XSTATIC_0 + i, REG_RW); + } +} + +static inline void +setBitRange(uint32_t &x, uint32_t value, unsigned high, unsigned low) +{ + assert(high >= low && high < 32); + unsigned shift = low; + unsigned mask = makeMask(high - low + 1); + x &= ~mask; + x |= (value & mask) << shift; +} + +static inline void setBit(uint32_t &x, uint32_t value, unsigned bit) +{ + return setBitRange(x, value, bit, bit); +} + +static inline uint32_t getBits(uint32_t value, unsigned shift, unsigned size) +{ + return (value >> shift) & ((1 << size) - 1); +} + +static inline uint32_t getBitRange(uint32_t value, unsigned high, unsigned low) +{ + return getBits(value, low, 1 + high - low); +} + +static inline uint32_t getBit(uint32_t value, unsigned shift) +{ + return getBits(value, shift, 1); +} + +static uint32_t readXLinkStateReg(const Node *node, const XLink &xLink) +{ + unsigned value = 0; + if (node->getType() == Node::XS1_G) { + setBitRange(value, xLink.getInterTokenDelay(), 3, 0); + setBitRange(value, xLink.getInterSymbolDelay(), 11, 8); + } else { + setBitRange(value, xLink.getInterTokenDelay(), 10, 0); + setBitRange(value, xLink.getInterSymbolDelay(), 21, 11); + } + bool isConnected = xLink.isConnected(); + if (node->getType() != Node::XS1_G) { + setBit(value, isConnected, 25); + setBit(value, isConnected, 26); + } + setBit(value, xLink.isFiveWire(), 30); + setBit(value, xLink.isEnabled(), 31); + return value; +} + +static void writeXLinkStateReg(const Node *node, XLink &xLink, uint32_t value) +{ + if (node->getType() == Node::XS1_G) { + xLink.setInterTokenDelay(getBitRange(value, 3, 0)); + xLink.setInterSymbolDelay(getBitRange(value, 11, 8)); + } else { + xLink.setInterTokenDelay(getBitRange(value, 10, 0)); + xLink.setInterSymbolDelay(getBitRange(value, 21, 11)); + } + // Ignore RESET and HELLO. + xLink.setFiveWire(getBit(value, 30)); + xLink.setEnabled(getBit(value, 31)); +} + +static unsigned getDirectionBits(const Node *node) +{ + if (node->getNodeNumberBits() == 0) + return 0; + return 32 - countLeadingZeros(node->getNodeNumberBits() - 1); +} + +static uint32_t +readXLinkDirectionAndNetworkReg(const Node *node, const XLink &xLink) +{ + unsigned value = 0; + unsigned directionBits = getDirectionBits(node); + setBitRange(value, xLink.getNetwork(), 5, 4); + setBitRange(value, xLink.getDirection(), 8 + directionBits + 1, 8); + return value; +} + +static void +writeXLinkDirectionAndNetworkReg(const Node *node, XLink &xLink, uint32_t value) +{ + unsigned directionBits = getDirectionBits(node); + xLink.setNetwork(getBitRange(value, 5, 4)); + xLink.setDirection(getBitRange(value, 8 + directionBits + 1, 8)); +} + +static uint32_t readDirectionReg(const Node *node, unsigned offset) +{ + unsigned value = 0; + unsigned end = std::min(offset + 4, node->getNodeNumberBits()); + for (unsigned i = offset; i < end; ++i) { + value |= node->getDirection(i) << ((i - offset) * 4); + } + return value; +} + +static void writeDirectionReg(Node *node, unsigned offset, uint32_t value) +{ + unsigned end = std::min(offset + 4, node->getNodeNumberBits()); + for (unsigned i = offset; i < end; ++i) { + unsigned direction = (value >> ((i - offset) * 4)) & 0xf; + node->setDirection(i, direction); + } +} + +bool SSwitchCtrlRegs::read(uint16_t num, uint32_t &result) +{ + using namespace SSwitchReg; + if (num > regFlags.size()) + return false; + if ((regFlags[num] & REG_READ) == 0) + return false; + if (num >= SLINK_0 && num < PLINK_0) { + result = readXLinkDirectionAndNetworkReg(node, + node->getXLink(num - SLINK_0)); + } + if (num >= XLINK_0 && num < XSTATIC_0) { + result = readXLinkStateReg(node, node->getXLink(num - XLINK_0)); + return true; + } + switch (num) { + case DIMENSION_DIRECTION_0: + case DIMENSION_DIRECTION_1: + result = readDirectionReg(node, (num - DIMENSION_DIRECTION_0) * 4); + return true; + case NODE_ID: + result = node->getNodeID(); + return true; + case DEVICE_ID3: + result = scratchReg; + return true; + } + assert(0 && "Unexpected register"); + return false; +} + +bool SSwitchCtrlRegs::write(uint16_t num, uint32_t value) +{ + using namespace SSwitchReg; + if (num > regFlags.size()) + return false; + if ((regFlags[num] & REG_WRITE) == 0) + return false; + if (num >= SLINK_0 && num < PLINK_0) { + writeXLinkDirectionAndNetworkReg(node, + node->getXLink(num - SLINK_0), value); + return true; + } + if (num >= XLINK_0 && num < XSTATIC_0) { + writeXLinkStateReg(node, node->getXLink(num - XLINK_0), value); + return true; + } + switch (num) { + case DIMENSION_DIRECTION_0: + case DIMENSION_DIRECTION_1: + writeDirectionReg(node, (num - DIMENSION_DIRECTION_0) * 4, value); + return true; + case NODE_ID: + node->setNodeID(value & makeMask(node->getNodeNumberBits())); + return true; + case DEVICE_ID3: + scratchReg = value; + return true; + } + assert(0 && "Unexpected register"); + return false; +} diff --git a/SSwitchCtrlRegs.h b/SSwitchCtrlRegs.h new file mode 100644 index 0000000..1787d49 --- /dev/null +++ b/SSwitchCtrlRegs.h @@ -0,0 +1,32 @@ +// Copyright (c) 2011-2012, Richard Osborne, All rights reserved +// This software is freely distributable under a derivative of the +// University of Illinois/NCSA Open Source License posted in +// LICENSE.txt and at + +#ifndef _SSwitchCtrlRegs_h_ +#define _SSwitchCtrlRegs_h_ + +#include +#include + +class Node; + +class SSwitchCtrlRegs { +private: + Node *node; + uint32_t scratchReg; + std::vector regFlags; + enum RegisterFlags { + REG_READ = 1, + REG_WRITE = 1 << 1, + REG_RW = REG_READ | REG_WRITE + }; + void initReg(unsigned num, uint8_t flags); +public: + SSwitchCtrlRegs(Node *n); + void initRegisters(); + bool read(uint16_t num, uint32_t &result); + bool write(uint16_t num, uint32_t value); +}; + +#endif //_SSwitchCtrlRegs_h_ diff --git a/SymbolInfo.cpp b/SymbolInfo.cpp index 2d39508..e52bd5d 100644 --- a/SymbolInfo.cpp +++ b/SymbolInfo.cpp @@ -92,7 +92,11 @@ SymbolInfo::~SymbolInfo() void SymbolInfo::add(const Core *core, std::auto_ptr info) { - coreMap.insert(std::make_pair(core, info.release())); + CoreSymbolInfo *&entry = coreMap[core]; + if (entry) { + delete entry; + } + entry = info.release(); } CoreSymbolInfo *SymbolInfo::getCoreSymbolInfo(const Core *core) const diff --git a/SyscallHandler.cpp b/SyscallHandler.cpp index 42a5527..e3199f7 100644 --- a/SyscallHandler.cpp +++ b/SyscallHandler.cpp @@ -38,8 +38,7 @@ class SyscallHandlerImpl { private: const scoped_array fds; bool tracing; - unsigned coreCount; - unsigned doneCount; + unsigned doneSyscallsRequired; char *getString(Thread &thread, uint32_t address); void *getBuffer(Thread &thread, uint32_t address, uint32_t size); int getNewFd(); @@ -52,7 +51,7 @@ class SyscallHandlerImpl { public: SyscallHandlerImpl(); - void setCoreCount(unsigned count) { coreCount = count; } + void setDoneSyscallsRequired(unsigned count) { doneSyscallsRequired = count; } SyscallHandler::SycallOutcome doSyscall(Thread &thread, int &retval); void doException(const Thread &thread); @@ -102,7 +101,7 @@ enum OpenFlags { const unsigned MAX_FDS = 512; SyscallHandlerImpl::SyscallHandlerImpl() : - fds(new int[MAX_FDS]), tracing(false), coreCount(1), doneCount(0) + fds(new int[MAX_FDS]), tracing(false), doneSyscallsRequired(1) { // Duplicate the standard file descriptors. fds[0] = dup(STDIN_FILENO); @@ -261,8 +260,7 @@ doSyscall(Thread &thread, int &retval) return SyscallHandler::EXIT; case OSCALL_DONE: TRACE("done"); - doneCount++; - if (doneCount == coreCount) { + if (--doneSyscallsRequired == 0) { retval = 0; return SyscallHandler::EXIT; } @@ -430,9 +428,9 @@ doSyscall(Thread &thread, int &retval) SyscallHandlerImpl SyscallHandlerImpl::instance; -void SyscallHandler::setCoreCount(unsigned number) +void SyscallHandler::setDoneSyscallsRequired(unsigned number) { - SyscallHandlerImpl::instance.setCoreCount(number); + SyscallHandlerImpl::instance.setDoneSyscallsRequired(number); } SyscallHandler::SycallOutcome SyscallHandler:: diff --git a/SyscallHandler.h b/SyscallHandler.h index ff328e0..d3d33df 100644 --- a/SyscallHandler.h +++ b/SyscallHandler.h @@ -13,7 +13,7 @@ class SyscallHandler { DESCHEDULE, EXIT }; - static void setCoreCount(unsigned number); + static void setDoneSyscallsRequired(unsigned number); static SycallOutcome doSyscall(Thread &thread, int &retval); static void doException(const Thread &thread); }; diff --git a/SystemState.cpp b/SystemState.cpp index fe8d70a..a2bacb1 100644 --- a/SystemState.cpp +++ b/SystemState.cpp @@ -58,29 +58,6 @@ completeEvent(Thread &t, EventableResource &res, bool interrupt) } } -ChanEndpoint *SystemState::getChanendDest(ResourceID ID) -{ - unsigned coreID = ID.node(); - // TODO build lookup map. - - for (node_iterator outerIt = node_begin(), outerE = node_end(); - outerIt != outerE; ++outerIt) { - Node &node = **outerIt; - for (Node::core_iterator innerIt = node.core_begin(), - innerE = node.core_end(); innerIt != innerE; ++innerIt) { - Core &core = **innerIt; - if (core.getCoreID() == coreID) { - ChanEndpoint *result; - bool isLocal = core.getLocalChanendDest(ID, result); - assert(isLocal); - (void)isLocal; - return result; - } - } - } - return 0; -} - int SystemState::run() { try { diff --git a/SystemState.h b/SystemState.h index 1d3433d..a7e5b89 100644 --- a/SystemState.h +++ b/SystemState.h @@ -91,7 +91,6 @@ class SystemState { return pendingEvent.set; } - ChanEndpoint *getChanendDest(ResourceID ID); node_iterator node_begin() { return nodes.begin(); } node_iterator node_end() { return nodes.end(); } const_node_iterator node_begin() const { return nodes.begin(); } diff --git a/Trace.h b/Trace.h index fae001d..1c16248 100644 --- a/Trace.h +++ b/Trace.h @@ -134,6 +134,7 @@ class Tracer { void setTracingEnabled(bool enable) { tracingEnabled = enable; } bool getTracingEnabled() const { return tracingEnabled; } void setSymbolInfo(std::auto_ptr &si); + SymbolInfo *getSymbolInfo() { return symInfo.get(); } void setColour(bool enable); template diff --git a/XE.cpp b/XE.cpp index 03bf3dc..cb4c84e 100644 --- a/XE.cpp +++ b/XE.cpp @@ -6,6 +6,7 @@ #include "XE.h" #include #include +#include bool XESector::getData(char *buf) const { @@ -29,6 +30,16 @@ bool XEElfSector::getElfData(char *buf) const return getParent().s.good(); } +XECallOrGotoSector:: +XECallOrGotoSector(XE &xe, uint64_t off, uint16_t type, uint64_t len) +: XESector(xe, off, type, len) +{ + assert(type == XE_SECTOR_CALL || type == XE_SECTOR_GOTO); + node = xe.ReadU16(); + core = xe.ReadU16(); + address = xe.ReadU64(); +} + XE::XE(const char *filename) : s(filename, std::ifstream::in | std::ifstream::binary), error(false) @@ -120,6 +131,10 @@ bool XE::ReadHeader() { case XESector::XE_SECTOR_ELF: sectors.push_back(new XEElfSector(*this, off, length - padding)); break; + case XESector::XE_SECTOR_CALL: + case XESector::XE_SECTOR_GOTO: + sectors.push_back(new XECallOrGotoSector(*this, off, type, length - padding)); + break; case XESector::XE_SECTOR_LAST: return true; default: diff --git a/XE.h b/XE.h index c0f99ed..4193357 100644 --- a/XE.h +++ b/XE.h @@ -18,6 +18,8 @@ class XESector { XE_SECTOR_BINARY = 1, XE_SECTOR_ELF = 2, XE_SECTOR_CONFIG = 3, + XE_SECTOR_GOTO = 5, + XE_SECTOR_CALL = 6, XE_SECTOR_LAST = 0x5555, }; private: @@ -50,6 +52,18 @@ class XEElfSector : public XESector { uint64_t getElfSize() const { return getLength() - 12; } }; +class XECallOrGotoSector : public XESector { +private: + uint16_t node; + uint16_t core; + uint64_t address; +public: + XECallOrGotoSector(XE &xe, uint64_t off, uint16_t t, uint64_t len); + uint16_t getNode() const { return node; }; + uint16_t getCore() const { return core; }; + uint64_t getAddress() const { return address; }; +}; + class XE { public: XE(const char *filename); @@ -59,7 +73,7 @@ class XE { bool operator!() const { return error; } - + void close() { s.close(); } @@ -78,6 +92,7 @@ class XE { friend class XESector; friend class XEElfSector; + friend class XECallOrGotoSector; }; #endif //_XE_h_ diff --git a/main.cpp b/main.cpp index bcbc8a5..9e033ea 100644 --- a/main.cpp +++ b/main.cpp @@ -152,7 +152,7 @@ static void readElf(const char *filename, const XEElfSector *elfSector, std::cerr << "Error reading elf data from \"" << filename << "\"" << std::endl; std::exit(1); } - + if (elf_version(EV_CURRENT) == EV_NONE) { std::cerr << "ELF library intialisation failed: " << elf_errmsg(-1) << std::endl; @@ -184,6 +184,7 @@ static void readElf(const char *filename, const XEElfSector *elfSector, std::cerr << "No ELF program headers" << std::endl; std::exit(1); } + core.resetCaches(); uint32_t ram_base = core.ram_base; uint32_t ram_size = core.getRamSize(); for (unsigned i = 0; i < num_phdrs; i++) { @@ -209,7 +210,7 @@ static void readElf(const char *filename, const XEElfSector *elfSector, } readSymbols(e, ram_base, ram_base + ram_size, SI); - + elf_end(e); } @@ -312,7 +313,13 @@ createNodeFromConfig(xmlNode *config, std::cerr << "Unknown jtagId 0x" << std::hex << jtagID << std::dec << '\n'; std::exit(1); } - std::auto_ptr node(new Node(nodeType)); + long numXLinks = 0; + if (xmlNode *switchNode = findChild(config, "Switch")) { + if (findAttribute(switchNode, "sLinks")) { + numXLinks = readNumberAttribute(switchNode, "sLinks"); + } + } + std::auto_ptr node(new Node(nodeType, numXLinks)); long nodeID = readNumberAttribute(config, "number"); nodeNumberMap.insert(std::make_pair(nodeID, node.get())); for (xmlNode *child = config->children; child; child = child->next) { @@ -321,10 +328,34 @@ createNodeFromConfig(xmlNode *config, continue; node->addCore(createCoreFromConfig(child)); } - node->setNodeID(nodeID); return node; } +static bool parseXLinkEnd(xmlAttr *attr, long &node, long &xlink) +{ + const char *s = (char*)attr->children->content; + errno = 0; + char *endp; + node = std::strtol(s, &endp, 0); + if (errno != 0 || *endp != ',') + return false; + xlink = std::strtol(endp + 1, &endp, 0); + if (errno != 0 || *endp != '\0') + return false; + return true; +} + +static Node * +lookupNodeChecked(const std::map &nodeNumberMap, unsigned nodeID) +{ + std::map::const_iterator it = nodeNumberMap.find(nodeID); + if (it == nodeNumberMap.end()) { + std::cerr << "No node matching id " << nodeID << std::endl; + std::exit(1); + } + return it->second; +} + static inline std::auto_ptr createSystemFromConfig(const char *filename, const XESector *configSector) { @@ -370,6 +401,33 @@ createSystemFromConfig(const char *filename, const XESector *configSector) continue; systemState->addNode(createNodeFromConfig(child, nodeNumberMap)); } + xmlNode *connections = findChild(system, "Connections"); + for (xmlNode *child = connections->children; child; child = child->next) { + if (child->type != XML_ELEMENT_NODE || + strcmp("SLink", (char*)child->name) != 0) + continue; + long nodeID1, link1, nodeID2, link2; + if (!parseXLinkEnd(findAttribute(child, "end1"), nodeID1, link1)) { + std::cerr << "Failed to parse \"end1\" attribute" << std::endl; + std::exit(1); + } + if (!parseXLinkEnd(findAttribute(child, "end2"), nodeID2, link2)) { + std::cerr << "Failed to parse \"end2\" attribute" << std::endl; + std::exit(1); + } + Node *node1 = lookupNodeChecked(nodeNumberMap, nodeID1); + if (link1 >= node1->getNumXLinks()) { + std::cerr << "Invalid sLink number " << link1 << std::endl; + std::exit(1); + } + Node *node2 = lookupNodeChecked(nodeNumberMap, nodeID2); + if (link2 >= node2->getNumXLinks()) { + std::cerr << "Invalid sLink number " << link2 << std::endl; + std::exit(1); + } + node1->connectXLink(link1, node2, link2); + node2->connectXLink(link2, node1, link1); + } xmlNode *jtag = findChild(system, "JtagChain"); unsigned jtagIndex = 0; for (xmlNode *child = jtag->children; child; child = child->next) { @@ -377,12 +435,7 @@ createSystemFromConfig(const char *filename, const XESector *configSector) strcmp("Node", (char*)child->name) != 0) continue; long nodeID = readNumberAttribute(child, "id"); - std::map::iterator it = nodeNumberMap.find(nodeID); - if (it == nodeNumberMap.end()) { - std::cerr << "No node matching id " << nodeID << std::endl; - std::exit(1); - } - it->second->setJtagIndex(jtagIndex++); + lookupNodeChecked(nodeNumberMap, nodeID)->setJtagIndex(jtagIndex++); } systemState->finalize(); xmlFreeDoc(doc); @@ -416,11 +469,9 @@ addToCoreMap(std::map,Core*> &coreMap, } static inline std::auto_ptr -readXE(const char *filename, SymbolInfo &SI, - std::set &coresWithImage, std::map &entryPoints) +readXE(XE &xe, const char *filename) { // Load the file into memory. - XE xe(filename); if (!xe) { std::cerr << "Error opening \"" << filename << "\"" << std::endl; std::exit(1); @@ -428,40 +479,35 @@ readXE(const char *filename, SymbolInfo &SI, // TODO handle XEs / XBs without a config sector. const XESector *configSector = xe.getConfigSector(); if (!configSector) { - std::cerr << "Error: No config file found in \"" << filename << "\"" << std::endl; + std::cerr << "Error: No config file found in \""; + std::cerr << filename << "\"" << std::endl; std::exit(1); } std::auto_ptr system = createSystemFromConfig(filename, configSector); - std::map,Core*> coreMap; - addToCoreMap(coreMap, *system); - for (std::vector::const_reverse_iterator - it = xe.getSectors().rbegin(), end = xe.getSectors().rend(); it != end; + return system; +} + +static int runCores(SystemState &sys, const std::set &cores, + const std::map &entryPoints) +{ + for (std::set::iterator it = cores.begin(), e = cores.end(); it != e; ++it) { - switch((*it)->getType()) { - case XESector::XE_SECTOR_ELF: - { - const XEElfSector *elfSector = static_cast(*it); - unsigned jtagIndex = elfSector->getNode(); - unsigned coreNum = elfSector->getCore(); - Core *core = coreMap[std::make_pair(jtagIndex, coreNum)]; - if (!core) { - std::cerr << "Error: cannot find node " << jtagIndex - << ", core " << coreNum << std::endl; - std::exit(1); - } - if (coresWithImage.count(core)) - continue; - std::auto_ptr CSI; - readElf(filename, elfSector, *core, CSI, entryPoints); - SI.add(core, CSI); - coresWithImage.insert(core); - break; + Core *core = *it; + sys.schedule(core->getThread(0)); + std::map::const_iterator match; + if ((match = entryPoints.find(core)) != entryPoints.end()) { + uint32_t entryPc = core->physicalAddress(match->second) >> 1; + if (core->isValidPc(entryPc)) { + core->getThread(0).pc = entryPc; + } else { + std::cout << "Warning: invalid ELF entry point 0x"; + std::cout << std::hex << match->second << std::dec << "\n"; } } } - xe.close(); - return system; + SyscallHandler::setDoneSyscallsRequired(cores.size()); + return sys.run(); } typedef std::vector > @@ -472,22 +518,19 @@ loop(const char *filename, const LoopbackPorts &loopbackPorts, const std::string &vcdFile, const PeripheralDescriptorWithPropertiesVector &peripherals) { - std::auto_ptr SI(new SymbolInfo); - std::set coresWithImage; - std::map entryPoints; - std::auto_ptr statePtr = readXE(filename, *SI, coresWithImage, - entryPoints); + XE xe(filename); + std::auto_ptr statePtr = readXE(xe, filename); SystemState &sys = *statePtr; - + if (!connectLoopbackPorts(sys, loopbackPorts)) { std::exit(1); } - + for (PeripheralDescriptorWithPropertiesVector::const_iterator it = peripherals.begin(), e = peripherals.end(); it != e; ++it) { it->first->createInstance(sys, it->second); } - + std::auto_ptr waveformTracer; // TODO update to handle multiple cores. if (!vcdFile.empty()) { @@ -495,40 +538,122 @@ loop(const char *filename, const LoopbackPorts &loopbackPorts, connectWaveformTracer(sys, *waveformTracer); } - for (std::set::iterator it = coresWithImage.begin(), - e = coresWithImage.end(); it != e; ++it) { - Core *core = *it; - sys.schedule(core->getThread(0)); + std::map,Core*> coreMap; + addToCoreMap(coreMap, *statePtr); + + std::auto_ptr SIAutoPtr(new SymbolInfo); + Tracer::get().setSymbolInfo(SIAutoPtr); + SymbolInfo *SI = Tracer::get().getSymbolInfo(); - // Patch in syscall instruction at the syscall address. - if (const ElfSymbol *syscallSym = SI->getGlobalSymbol(core, "_DoSyscall")) { - if (!core->setSyscallAddress(syscallSym->value)) { - std::cout << "Warning: invalid _DoSyscall address " - << std::hex << syscallSym->value << std::dec << "\n"; + std::map entryPoints; + std::set gotoSectors; + std::set callSectors; + for (std::vector::const_iterator + it = xe.getSectors().begin(), end = xe.getSectors().end(); it != end; + ++it) { + switch((*it)->getType()) { + case XESector::XE_SECTOR_ELF: + { + const XEElfSector *elfSector = static_cast(*it); + unsigned jtagIndex = elfSector->getNode(); + unsigned coreNum = elfSector->getCore(); + Core *core = coreMap[std::make_pair(jtagIndex, coreNum)]; + if (!core) { + std::cerr << "Error: cannot find node " << jtagIndex + << ", core " << coreNum << std::endl; + std::exit(1); + } + if (gotoSectors.count(core)) { + // Shouldn't happen. + return runCores(sys, gotoSectors, entryPoints); + } + if (callSectors.count(core)) { + int status = runCores(sys, callSectors, entryPoints); + if (status != 0) + return status; + callSectors.clear(); + } + std::auto_ptr CSI; + readElf(filename, elfSector, *core, CSI, entryPoints); + SI->add(core, CSI); + // TODO check old instructions are cleared. + + // Patch in syscall instruction at the syscall address. + if (const ElfSymbol *syscallSym = SI->getGlobalSymbol(core, "_DoSyscall")) { + if (!core->setSyscallAddress(syscallSym->value)) { + std::cout << "Warning: invalid _DoSyscall address " + << std::hex << syscallSym->value << std::dec << "\n"; + } + } + // Patch in exception instruction at the exception address + if (const ElfSymbol *doExceptionSym = SI->getGlobalSymbol(core, "_DoException")) { + if (!core->setExceptionAddress(doExceptionSym->value)) { + std::cout << "Warning: invalid _DoException address " + << std::hex << doExceptionSym->value << std::dec << "\n"; + } + } } - } - // Patch in exception instruction at the exception address - if (const ElfSymbol *doExceptionSym = SI->getGlobalSymbol(core, "_DoException")) { - if (!core->setExceptionAddress(doExceptionSym->value)) { - std::cout << "Warning: invalid _DoException address " - << std::hex << doExceptionSym->value << std::dec << "\n"; + break; + case XESector::XE_SECTOR_CALL: + { + const XECallOrGotoSector *callSector = + static_cast(*it); + if (!gotoSectors.empty()) { + // Shouldn't happen. + return runCores(sys, gotoSectors, entryPoints); + } + unsigned jtagIndex = callSector->getNode(); + unsigned coreNum = callSector->getCore(); + Core *core = coreMap[std::make_pair(jtagIndex, coreNum)]; + if (!core) { + std::cerr << "Error: cannot find node " << jtagIndex + << ", core " << coreNum << std::endl; + std::exit(1); + } + if (!callSectors.insert(core).second) { + int status = runCores(sys, callSectors, entryPoints); + if (status != 0) + return status; + callSectors.clear(); + callSectors.insert(core); + } } - } - std::map::iterator match; - if ((match = entryPoints.find(core)) != entryPoints.end()) { - uint32_t entryPc = core->physicalAddress(match->second) >> 1; - if (core->isValidPc(entryPc)) { - core->getThread(0).pc = entryPc; - } else { - std::cout << "Warning: invalid ELF entry point 0x"; - std::cout << std::hex << match->second << std::dec << "\n"; + break; + case XESector::XE_SECTOR_GOTO: + { + const XECallOrGotoSector *gotoSector = + static_cast(*it); + if (!callSectors.empty()) { + // Handle calls. + int status = runCores(sys, callSectors, entryPoints); + if (status != 0) + return status; + callSectors.clear(); + } + unsigned jtagIndex = gotoSector->getNode(); + unsigned coreNum = gotoSector->getCore(); + Core *core = coreMap[std::make_pair(jtagIndex, coreNum)]; + if (!core) { + std::cerr << "Error: cannot find node " << jtagIndex + << ", core " << coreNum << std::endl; + std::exit(1); + } + if (!gotoSectors.insert(core).second) { + // Shouldn't happen. + return runCores(sys, gotoSectors, entryPoints); + } } + break; } } - SyscallHandler::setCoreCount(coresWithImage.size()); - - Tracer::get().setSymbolInfo(SI); - return sys.run(); + if (!gotoSectors.empty()) { + return runCores(sys, gotoSectors, entryPoints); + } + if (!callSectors.empty()) { + // Shouldn't happen. + return runCores(sys, callSectors, entryPoints); + } + return 0; } static void loopbackOption(const char *a, const char *b, LoopbackPorts &loopbackPorts) diff --git a/test/multicore_2g4.xc b/test/multicore_2g4.xc new file mode 100644 index 0000000..84fbffb --- /dev/null +++ b/test/multicore_2g4.xc @@ -0,0 +1,21 @@ +// RUN: xcc %s.xn %s -o %t1.xe +// RUN: axe %t1.xe > %t2.txt +// RUN: cmp %t2.txt %s.expect + +#include +#include + +int main() +{ + par { + on stdcore[0]: printstr("hello\n"); + on stdcore[1]: printstr("hello\n"); + on stdcore[2]: printstr("hello\n"); + on stdcore[3]: printstr("hello\n"); + on stdcore[4]: printstr("hello\n"); + on stdcore[5]: printstr("hello\n"); + on stdcore[6]: printstr("hello\n"); + on stdcore[7]: printstr("hello\n"); + } + return 0; +} diff --git a/test/multicore_2g4.xc.expect b/test/multicore_2g4.xc.expect new file mode 100644 index 0000000..cc21e55 --- /dev/null +++ b/test/multicore_2g4.xc.expect @@ -0,0 +1,8 @@ +hello +hello +hello +hello +hello +hello +hello +hello diff --git a/test/multicore_2g4.xc.xn b/test/multicore_2g4.xc.xn new file mode 100644 index 0000000..ec986b1 --- /dev/null +++ b/test/multicore_2g4.xc.xn @@ -0,0 +1,46 @@ + + + + + core stdcore[8] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +