OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [bench/] [sysc/] [src/] [GdbServerSC.cpp] - Diff between revs 462 and 861

Only display areas with differences | Details | Blame | View Log

Rev 462 Rev 861
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
 
// SystemC GDB RSP server: implementation
// SystemC GDB RSP server: implementation
 
 
// Copyright (C) 2008  Embecosm Limited <info@embecosm.com>
// Copyright (C) 2008  Embecosm Limited <info@embecosm.com>
 
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
// Contributor Julius Baxter <julius@orsoc.se>
// Contributor Julius Baxter <julius@orsoc.se>
 
 
// This file is part of the GDB interface to the cycle accurate model of the
// This file is part of the GDB interface to the cycle accurate model of the
// OpenRISC 1000 based system-on-chip, ORPSoC, built using Verilator.
// OpenRISC 1000 based system-on-chip, ORPSoC, built using Verilator.
 
 
// This program is free software: you can redistribute it and/or modify it
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or (at your
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
// option) any later version.
 
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// License for more details.
// License for more details.
 
 
// You should have received a copy of the GNU Lesser General Public License
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
 
// $Id$
// $Id$
 
 
#include <iostream>
#include <iostream>
#include <iomanip>
#include <iomanip>
 
 
#include "GdbServerSC.h"
#include "GdbServerSC.h"
#include "Utils.h"
#include "Utils.h"
 
 
#include <errno.h>
#include <errno.h>
#include <fcntl.h>
#include <fcntl.h>
 
#include <unistd.h>
extern int monitor_to_gdb_pipe[2][2];   // [0][] - monitor to gdb, [1][] - gdb to monitor, [][0] - read, [][1] - write
extern int monitor_to_gdb_pipe[2][2];   // [0][] - monitor to gdb, [1][] - gdb to monitor, [][0] - read, [][1] - write
 
 
using std::cerr;
using std::cerr;
using std::dec;
using std::dec;
using std::endl;
using std::endl;
using std::hex;
using std::hex;
 
 
using sc_core::sc_fifo;
using sc_core::sc_fifo;
using sc_core::sc_module_name;
using sc_core::sc_module_name;
using sc_core::sc_stop;
using sc_core::sc_stop;
using sc_core::sc_time;
using sc_core::sc_time;
 
 
SC_HAS_PROCESS(GdbServerSC);
SC_HAS_PROCESS(GdbServerSC);
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Constructor for the GDB RSP server.
//! Constructor for the GDB RSP server.
 
 
//! We create a SC_THREAD which will act as the listener. Must be a
//! We create a SC_THREAD which will act as the listener. Must be a
//! thread, since we need to wait for the actions to complete.
//! thread, since we need to wait for the actions to complete.
 
 
//! The current scan chain is marked as undefined.
//! The current scan chain is marked as undefined.
 
 
//! This makes use of the Embecosm cycle accurate SystemC JTAG interface.
//! This makes use of the Embecosm cycle accurate SystemC JTAG interface.
 
 
//! @see Embecosm Application Note 5 "Using JTAG with SystemC: Implementation
//! @see Embecosm Application Note 5 "Using JTAG with SystemC: Implementation
//!      of a Cycle Accurate Interface"
//!      of a Cycle Accurate Interface"
//!      (http://www.embecosm.com/download/ean5.html)
//!      (http://www.embecosm.com/download/ean5.html)
 
 
//! @todo We do not handle a user coded l.trap properly (i.e. one that is not
//! @todo We do not handle a user coded l.trap properly (i.e. one that is not
//!       a breakpoint). Effectively it is ignored, whereas we ought to set up
//!       a breakpoint). Effectively it is ignored, whereas we ought to set up
//!       the exception registers and redirect through the trap vector.
//!       the exception registers and redirect through the trap vector.
 
 
//! @param[in] name             Name of this module, passed to the parent
//! @param[in] name             Name of this module, passed to the parent
//!                             constructor. 
//!                             constructor. 
//! @param[in] _tapActionQueue  Pointer to fifo of actions to be performed by
//! @param[in] _tapActionQueue  Pointer to fifo of actions to be performed by
//!                             the JTAG interface
//!                             the JTAG interface
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
GdbServerSC::GdbServerSC(sc_module_name name,
GdbServerSC::GdbServerSC(sc_module_name name,
                         uint32_t _flashStart,
                         uint32_t _flashStart,
                         uint32_t _flashEnd,
                         uint32_t _flashEnd,
                         int rspPort,
                         int rspPort,
                         sc_fifo <
                         sc_fifo <
                         TapAction * >*tapActionQueue):sc_module(name),
                         TapAction * >*tapActionQueue):sc_module(name),
flashStart(_flashStart), flashEnd(_flashEnd)
flashStart(_flashStart), flashEnd(_flashEnd)
{
{
        pkt = new RspPacket(RSP_PKT_MAX);
        pkt = new RspPacket(RSP_PKT_MAX);
        rsp = new RspConnection(rspPort);
        rsp = new RspConnection(rspPort);
        debugUnit = new DebugUnitSC("debug-unit", tapActionQueue);
        debugUnit = new DebugUnitSC("debug-unit", tapActionQueue);
        mpHash = new MpHash();
        mpHash = new MpHash();
 
 
        /* Setup the pipes between or1200 monitor module and GDB stub */
        /* Setup the pipes between or1200 monitor module and GDB stub */
        pipe(monitor_to_gdb_pipe[0]);
        pipe(monitor_to_gdb_pipe[0]);
        pipe(monitor_to_gdb_pipe[1]);
        pipe(monitor_to_gdb_pipe[1]);
 
 
        // Set non-blocking reads
        // Set non-blocking reads
#ifdef O_NONBLOCK               /* The POSIX way */
#ifdef O_NONBLOCK               /* The POSIX way */
        fcntl(monitor_to_gdb_pipe[0][0], F_SETFL, O_NONBLOCK);
        fcntl(monitor_to_gdb_pipe[0][0], F_SETFL, O_NONBLOCK);
        fcntl(monitor_to_gdb_pipe[1][0], F_SETFL, O_NONBLOCK);
        fcntl(monitor_to_gdb_pipe[1][0], F_SETFL, O_NONBLOCK);
#elif defined (O_NDELAY)
#elif defined (O_NDELAY)
        fcntl(monitor_to_gdb_pipe[0][0], F_SETFL, O_NDELAY);
        fcntl(monitor_to_gdb_pipe[0][0], F_SETFL, O_NDELAY);
        fcntl(monitor_to_gdb_pipe[1][0], F_SETFL, O_NDELAY);
        fcntl(monitor_to_gdb_pipe[1][0], F_SETFL, O_NDELAY);
#endif /* O_NONBLOCK */
#endif /* O_NONBLOCK */
 
 
        SC_THREAD(rspServer);
        SC_THREAD(rspServer);
 
 
}                               // GdbServerSC ()
}                               // GdbServerSC ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Destructor
//! Destructor
 
 
//! Free up data structures
//! Free up data structures
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
GdbServerSC::~GdbServerSC()
GdbServerSC::~GdbServerSC()
{
{
        delete mpHash;
        delete mpHash;
        delete debugUnit;
        delete debugUnit;
        delete rsp;
        delete rsp;
        delete pkt;
        delete pkt;
 
 
}                               // ~GdbServerSC
}                               // ~GdbServerSC
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! SystemC thread to listen for RSP requests
//! SystemC thread to listen for RSP requests
 
 
//! JTAG actions will be queued as appropriate. Runs forever
//! JTAG actions will be queued as appropriate. Runs forever
 
 
//! We don't allow any actions until the target is out of its startup mode
//! We don't allow any actions until the target is out of its startup mode
//! (where the ROM is mapped into RAM space). This is determined by seeing if
//! (where the ROM is mapped into RAM space). This is determined by seeing if
//! the PPC is still in flash memory.
//! the PPC is still in flash memory.
 
 
//! Have to use a thread, since we will end up waiting for actions to
//! Have to use a thread, since we will end up waiting for actions to
//! complete.
//! complete.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void
void
 GdbServerSC::rspServer()
 GdbServerSC::rspServer()
{
{
        // Reset the debug unit, and wait for ORPSoC to be ready, by noting when it
        // Reset the debug unit, and wait for ORPSoC to be ready, by noting when it
        // accesses an address outside of flash. Note that we use NPC, not PPC since
        // accesses an address outside of flash. Note that we use NPC, not PPC since
        // at reset PPC is zero, and would trigger a false positive.
        // at reset PPC is zero, and would trigger a false positive.
 
 
        debugUnit->resetDebugUnit();
        debugUnit->resetDebugUnit();
        rsp_sigval = TARGET_SIGNAL_NONE;
        rsp_sigval = TARGET_SIGNAL_NONE;
        /*
        /*
           uint32_t npc;
           uint32_t npc;
           do
           do
           {
           {
           npc = debugUnit->readSpr (SPR_NPC);
           npc = debugUnit->readSpr (SPR_NPC);
           }
           }
           while ((flashStart <= npc) && (npc <= flashEnd));
           while ((flashStart <= npc) && (npc <= flashEnd));
         */
         */
        debugUnit->stall();
        debugUnit->stall();
        targetStopped = true;
        targetStopped = true;
 
 
        // Make sure we are connected.
        // Make sure we are connected.
        while (!rsp->isConnected()) {
        while (!rsp->isConnected()) {
                // Reconnect and stall the processor on a new connection
                // Reconnect and stall the processor on a new connection
                if (!rsp->rspConnect()) {
                if (!rsp->rspConnect()) {
                        // Serious failure. Must abort execution.
                        // Serious failure. Must abort execution.
                        cerr << "*** Unable to continue: ABORTING" << endl;
                        cerr << "*** Unable to continue: ABORTING" << endl;
                        sc_stop();
                        sc_stop();
                }
                }
                // Stall the processor until we get a command to handle.
                // Stall the processor until we get a command to handle.
                if (!debugUnit->isStalled()) {
                if (!debugUnit->isStalled()) {
                        debugUnit->stall();
                        debugUnit->stall();
                }
                }
 
 
                targetStopped = true;   // Processor now not running
                targetStopped = true;   // Processor now not running
        }
        }
 
 
        // Loop processing commands forever
        // Loop processing commands forever
        while (true) {
        while (true) {
                if (!rsp->isConnected()) {
                if (!rsp->isConnected()) {
                        sc_stop();
                        sc_stop();
                        return;
                        return;
                }
                }
                // Wait until the target has stopped. In this simplified implementation,
                // Wait until the target has stopped. In this simplified implementation,
                // the only reasons for stopping are hitting a breakpoint (l.trap),
                // the only reasons for stopping are hitting a breakpoint (l.trap),
                // hardware single stepping or hitting a non-breakpoint l.trap. This
                // hardware single stepping or hitting a non-breakpoint l.trap. This
                // last is not cleanly handled at the moment (we ought to redirect the
                // last is not cleanly handled at the moment (we ought to redirect the
                // restart through the trap exception vector).
                // restart through the trap exception vector).
                while (!targetStopped) {
                while (!targetStopped) {
 
 
                        /* First check to see if the or1200 monitor module wants us to stall */
                        /* First check to see if the or1200 monitor module wants us to stall */
                        if (checkMonitorPipe())
                        if (checkMonitorPipe())
                                break;
                                break;
 
 
                        rspCheckForException();
                        rspCheckForException();
 
 
                        if (debugUnit->isStalled()) {
                        if (debugUnit->isStalled()) {
                                targetStopped = true;
                                targetStopped = true;
 
 
                                // If it's a breakpoint, then we need to back up one
                                // If it's a breakpoint, then we need to back up one
                                // instruction, so on restart we execute the actual
                                // instruction, so on restart we execute the actual
                                // instruction.
                                // instruction.
                                uint32_t ppc = debugUnit->readSpr(SPR_PPC);
                                uint32_t ppc = debugUnit->readSpr(SPR_PPC);
 
 
                                if (NULL != mpHash->lookup(BP_MEMORY, ppc)
                                if (NULL != mpHash->lookup(BP_MEMORY, ppc)
                                    && rsp_sigval == TARGET_SIGNAL_TRAP) {
                                    && rsp_sigval == TARGET_SIGNAL_TRAP) {
                                        writeNpc(ppc);
                                        writeNpc(ppc);
                                }
                                }
                                // Tell the client we've stopped.
                                // Tell the client we've stopped.
                                rspReportException();
                                rspReportException();
                        } else if (rsp->rspSocketPeek() > 0) {
                        } else if (rsp->rspSocketPeek() > 0) {
                                if (rsp->rspSocketPeek() == 0x03)       // ETX, end of text control char
                                if (rsp->rspSocketPeek() == 0x03)       // ETX, end of text control char
                                {
                                {
                                        // Got an interrupt command from GDB, this function should
                                        // Got an interrupt command from GDB, this function should
                                        // pull the packet off the socket and stall the processor.
                                        // pull the packet off the socket and stall the processor.
                                        // and then send a stop reply packet with signal 
                                        // and then send a stop reply packet with signal 
                                        // TARGET_SIGNAL_NONE.
                                        // TARGET_SIGNAL_NONE.
                                        rspInterrupt();
                                        rspInterrupt();
                                        targetStopped = true;   // Processor now not running
                                        targetStopped = true;   // Processor now not running
                                }
                                }
                        }
                        }
                }
                }
 
 
                // Get a RSP client request
                // Get a RSP client request
                rspClientRequest();
                rspClientRequest();
        }
        }
}                               // rspServer ()
}                               // rspServer ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Deal with a request from the GDB client session
//! Deal with a request from the GDB client session
 
 
//! In general, apart from the simplest requests, this function replies on
//! In general, apart from the simplest requests, this function replies on
//! other functions to implement the functionality.
//! other functions to implement the functionality.
 
 
//! @note It is the responsibility of the recipient to delete the packet when
//! @note It is the responsibility of the recipient to delete the packet when
//!       it is finished with. It is permissible to reuse the packet for a
//!       it is finished with. It is permissible to reuse the packet for a
//!       reply.
//!       reply.
 
 
//! @todo Is this the implementation of the 'D' packet really the intended
//! @todo Is this the implementation of the 'D' packet really the intended
//!       meaning? Or does it just mean that only vAttach will be recognized
//!       meaning? Or does it just mean that only vAttach will be recognized
//!       after this?
//!       after this?
 
 
//! @param[in] pkt  The received RSP packet
//! @param[in] pkt  The received RSP packet
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspClientRequest()
void GdbServerSC::rspClientRequest()
{
{
        if (!rsp->getPkt(pkt)) {
        if (!rsp->getPkt(pkt)) {
                rsp->rspClose();        // Comms failure
                rsp->rspClose();        // Comms failure
                return;
                return;
        }
        }
        //Uncomment the next line for the RSP client to print out every packet it gets from GDB
        //Uncomment the next line for the RSP client to print out every packet it gets from GDB
        //cerr << "rspClientRequest: " << pkt->data/*[0]*/ << endl;
        //cerr << "rspClientRequest: " << pkt->data/*[0]*/ << endl;
        switch (pkt->data[0]) {
        switch (pkt->data[0]) {
        case '!':
        case '!':
                // Request for extended remote mode
                // Request for extended remote mode
                pkt->packStr("OK");
                pkt->packStr("OK");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
 
 
        case '?':
        case '?':
                // Return last signal ID
                // Return last signal ID
                rspReportException();
                rspReportException();
                return;
                return;
 
 
        case 'A':
        case 'A':
                // Initialization of argv not supported
                // Initialization of argv not supported
                cerr << "Warning: RSP 'A' packet not supported: ignored" <<
                cerr << "Warning: RSP 'A' packet not supported: ignored" <<
                    endl;
                    endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
 
 
        case 'b':
        case 'b':
                // Setting baud rate is deprecated
                // Setting baud rate is deprecated
                cerr << "Warning: RSP 'b' packet is deprecated and not "
                cerr << "Warning: RSP 'b' packet is deprecated and not "
                    << "supported: ignored" << endl;
                    << "supported: ignored" << endl;
                return;
                return;
 
 
        case 'B':
        case 'B':
                // Breakpoints should be set using Z packets
                // Breakpoints should be set using Z packets
                cerr << "Warning: RSP 'B' packet is deprecated (use 'Z'/'z' "
                cerr << "Warning: RSP 'B' packet is deprecated (use 'Z'/'z' "
                    << "packets instead): ignored" << endl;
                    << "packets instead): ignored" << endl;
                return;
                return;
 
 
        case 'c':
        case 'c':
                // Continue
                // Continue
                rspContinue(EXCEPT_NONE);
                rspContinue(EXCEPT_NONE);
                return;
                return;
 
 
        case 'C':
        case 'C':
                // Continue with signal (in the packet)
                // Continue with signal (in the packet)
                rspContinue();
                rspContinue();
                return;
                return;
 
 
        case 'd':
        case 'd':
                // Disable debug using a general query
                // Disable debug using a general query
                cerr << "Warning: RSP 'd' packet is deprecated (define a 'Q' "
                cerr << "Warning: RSP 'd' packet is deprecated (define a 'Q' "
                    << "packet instead: ignored" << endl;
                    << "packet instead: ignored" << endl;
                return;
                return;
 
 
        case 'D':
        case 'D':
                // Detach GDB. Do this by closing the client. The rules say that
                // Detach GDB. Do this by closing the client. The rules say that
                // execution should continue, so unstall the processor.
                // execution should continue, so unstall the processor.
                pkt->packStr("OK");
                pkt->packStr("OK");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                rsp->rspClose();
                rsp->rspClose();
                //debugUnit->unstall ();      
                //debugUnit->unstall ();      
                return;
                return;
 
 
        case 'F':
        case 'F':
                // File I/O is not currently supported
                // File I/O is not currently supported
                cerr << "Warning: RSP file I/O not currently supported: 'F' "
                cerr << "Warning: RSP file I/O not currently supported: 'F' "
                    << "packet ignored" << endl;
                    << "packet ignored" << endl;
                return;
                return;
 
 
        case 'g':
        case 'g':
                rspReadAllRegs();
                rspReadAllRegs();
                return;
                return;
 
 
        case 'G':
        case 'G':
                rspWriteAllRegs();
                rspWriteAllRegs();
                return;
                return;
 
 
        case 'H':
        case 'H':
                // Set the thread number of subsequent operations. For now ignore
                // Set the thread number of subsequent operations. For now ignore
                // silently and just reply "OK"
                // silently and just reply "OK"
                pkt->packStr("OK");
                pkt->packStr("OK");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
 
 
        case 'i':
        case 'i':
        case 'I':
        case 'I':
                // Single cycle step not currently supported. Mark the target as
                // Single cycle step not currently supported. Mark the target as
                // running, so that next time it will be detected as stopped (it is
                // running, so that next time it will be detected as stopped (it is
                // still stalled in reality) and an ack sent back to the client.
                // still stalled in reality) and an ack sent back to the client.
                cerr << "Warning: RSP cycle stepping not supported: target "
                cerr << "Warning: RSP cycle stepping not supported: target "
                    << "stopped immediately" << endl;
                    << "stopped immediately" << endl;
                targetStopped = false;
                targetStopped = false;
                return;
                return;
 
 
        case 'k':
        case 'k':
                // Kill request. Do nothing for now.
                // Kill request. Do nothing for now.
                return;
                return;
 
 
        case 'm':
        case 'm':
                // Read memory (symbolic)
                // Read memory (symbolic)
                rspReadMem();
                rspReadMem();
                return;
                return;
 
 
        case 'M':
        case 'M':
                // Write memory (symbolic)
                // Write memory (symbolic)
                rspWriteMem();
                rspWriteMem();
                return;
                return;
 
 
        case 'p':
        case 'p':
                // Read a register
                // Read a register
                rspReadReg();
                rspReadReg();
                return;
                return;
 
 
        case 'P':
        case 'P':
                // Write a register
                // Write a register
                rspWriteReg();
                rspWriteReg();
                return;
                return;
 
 
        case 'q':
        case 'q':
                // Any one of a number of query packets
                // Any one of a number of query packets
                rspQuery();
                rspQuery();
                return;
                return;
 
 
        case 'Q':
        case 'Q':
                // Any one of a number of set packets
                // Any one of a number of set packets
                rspSet();
                rspSet();
                return;
                return;
 
 
        case 'r':
        case 'r':
                // Reset the system. Deprecated (use 'R' instead)
                // Reset the system. Deprecated (use 'R' instead)
                cerr << "Warning: RSP 'r' packet is deprecated (use 'R' "
                cerr << "Warning: RSP 'r' packet is deprecated (use 'R' "
                    << "packet instead): ignored" << endl;
                    << "packet instead): ignored" << endl;
                return;
                return;
 
 
        case 'R':
        case 'R':
                // Restart the program being debugged.
                // Restart the program being debugged.
                rspRestart();
                rspRestart();
                return;
                return;
 
 
        case 's':
        case 's':
                // Single step one machine instruction.
                // Single step one machine instruction.
                rspStep(EXCEPT_NONE);
                rspStep(EXCEPT_NONE);
                return;
                return;
 
 
        case 'S':
        case 'S':
                // Single step one machine instruction.
                // Single step one machine instruction.
                rspStep();
                rspStep();
                return;
                return;
 
 
        case 't':
        case 't':
                // Search. This is not well defined in the manual and for now we don't
                // Search. This is not well defined in the manual and for now we don't
                // support it. No response is defined.
                // support it. No response is defined.
                cerr << "Warning: RSP 't' packet not supported: ignored"
                cerr << "Warning: RSP 't' packet not supported: ignored"
                    << endl;
                    << endl;
                return;
                return;
 
 
        case 'T':
        case 'T':
                // Is the thread alive. We are bare metal, so don't have a thread
                // Is the thread alive. We are bare metal, so don't have a thread
                // context. The answer is always "OK".
                // context. The answer is always "OK".
                pkt->packStr("OK");
                pkt->packStr("OK");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
 
 
        case 'v':
        case 'v':
                // Any one of a number of packets to control execution
                // Any one of a number of packets to control execution
                rspVpkt();
                rspVpkt();
                return;
                return;
 
 
        case 'X':
        case 'X':
                // Write memory (binary)
                // Write memory (binary)
                rspWriteMemBin();
                rspWriteMemBin();
                return;
                return;
 
 
        case 'z':
        case 'z':
                // Remove a breakpoint/watchpoint.
                // Remove a breakpoint/watchpoint.
                rspRemoveMatchpoint();
                rspRemoveMatchpoint();
                return;
                return;
 
 
        case 'Z':
        case 'Z':
                // Insert a breakpoint/watchpoint.
                // Insert a breakpoint/watchpoint.
                rspInsertMatchpoint();
                rspInsertMatchpoint();
                return;
                return;
 
 
        default:
        default:
                // Unknown commands are ignored
                // Unknown commands are ignored
                cerr << "Warning: Unknown RSP request" << pkt->data << endl;
                cerr << "Warning: Unknown RSP request" << pkt->data << endl;
                return;
                return;
        }
        }
}                               // rspClientRequest ()
}                               // rspClientRequest ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Check if processor is stalled. If it is, read the DRR and return the
//! Check if processor is stalled. If it is, read the DRR and return the
//! target signal code.
//! target signal code.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspCheckForException()
void GdbServerSC::rspCheckForException()
{
{
 
 
        uint32_t drr;
        uint32_t drr;
 
 
        if (!debugUnit->isStalled()) {
        if (!debugUnit->isStalled()) {
                // Processor not stalled. Just return;
                // Processor not stalled. Just return;
                return;
                return;
        }
        }
 
 
        switch ((debugUnit->readSpr(SPR_DRR) & 0xffffffff)) {
        switch ((debugUnit->readSpr(SPR_DRR) & 0xffffffff)) {
        case SPR_DRR_RSTE:
        case SPR_DRR_RSTE:
                rsp_sigval = TARGET_SIGNAL_PWR;
                rsp_sigval = TARGET_SIGNAL_PWR;
                break;
                break;
        case SPR_DRR_BUSEE:
        case SPR_DRR_BUSEE:
                rsp_sigval = TARGET_SIGNAL_BUS;
                rsp_sigval = TARGET_SIGNAL_BUS;
                break;
                break;
        case SPR_DRR_DPFE:
        case SPR_DRR_DPFE:
                rsp_sigval = TARGET_SIGNAL_SEGV;
                rsp_sigval = TARGET_SIGNAL_SEGV;
                break;
                break;
        case SPR_DRR_IPFE:
        case SPR_DRR_IPFE:
                rsp_sigval = TARGET_SIGNAL_SEGV;
                rsp_sigval = TARGET_SIGNAL_SEGV;
                break;
                break;
        case SPR_DRR_TTE:
        case SPR_DRR_TTE:
                rsp_sigval = TARGET_SIGNAL_ALRM;
                rsp_sigval = TARGET_SIGNAL_ALRM;
                break;
                break;
        case SPR_DRR_AE:
        case SPR_DRR_AE:
                rsp_sigval = TARGET_SIGNAL_BUS;
                rsp_sigval = TARGET_SIGNAL_BUS;
                break;
                break;
        case SPR_DRR_IIE:
        case SPR_DRR_IIE:
                rsp_sigval = TARGET_SIGNAL_ILL;
                rsp_sigval = TARGET_SIGNAL_ILL;
                break;
                break;
        case SPR_DRR_IE:
        case SPR_DRR_IE:
                rsp_sigval = TARGET_SIGNAL_INT;
                rsp_sigval = TARGET_SIGNAL_INT;
                break;
                break;
        case SPR_DRR_DME:
        case SPR_DRR_DME:
                rsp_sigval = TARGET_SIGNAL_SEGV;
                rsp_sigval = TARGET_SIGNAL_SEGV;
                break;
                break;
        case SPR_DRR_IME:
        case SPR_DRR_IME:
                rsp_sigval = TARGET_SIGNAL_SEGV;
                rsp_sigval = TARGET_SIGNAL_SEGV;
                break;
                break;
        case SPR_DRR_RE:
        case SPR_DRR_RE:
                rsp_sigval = TARGET_SIGNAL_FPE;
                rsp_sigval = TARGET_SIGNAL_FPE;
                break;
                break;
        case SPR_DRR_SCE:
        case SPR_DRR_SCE:
                rsp_sigval = TARGET_SIGNAL_USR2;
                rsp_sigval = TARGET_SIGNAL_USR2;
                break;
                break;
        case SPR_DRR_FPE:
        case SPR_DRR_FPE:
                rsp_sigval = TARGET_SIGNAL_FPE;
                rsp_sigval = TARGET_SIGNAL_FPE;
                break;
                break;
        case SPR_DRR_TE:
        case SPR_DRR_TE:
                rsp_sigval = TARGET_SIGNAL_TRAP;
                rsp_sigval = TARGET_SIGNAL_TRAP;
                break;
                break;
 
 
        default:
        default:
                // This must be the case of single step (which does not set DRR)
                // This must be the case of single step (which does not set DRR)
                rsp_sigval = TARGET_SIGNAL_TRAP;
                rsp_sigval = TARGET_SIGNAL_TRAP;
                break;
                break;
        }
        }
 
 
        return;
        return;
}
}
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Send a packet acknowledging an exception has occurred
//! Send a packet acknowledging an exception has occurred
 
 
//! The only signal we ever see in this implementation is TRAP.
//! The only signal we ever see in this implementation is TRAP.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspReportException()
void GdbServerSC::rspReportException()
{
{
        // Construct a signal received packet
        // Construct a signal received packet
        pkt->data[0] = 'S';
        pkt->data[0] = 'S';
        pkt->data[1] = Utils::hex2Char(rsp_sigval >> 4);
        pkt->data[1] = Utils::hex2Char(rsp_sigval >> 4);
        pkt->data[2] = Utils::hex2Char(rsp_sigval % 16);
        pkt->data[2] = Utils::hex2Char(rsp_sigval % 16);
        pkt->data[3] = '\0';
        pkt->data[3] = '\0';
        pkt->setLen(strlen(pkt->data));
        pkt->setLen(strlen(pkt->data));
 
 
        rsp->putPkt(pkt);
        rsp->putPkt(pkt);
 
 
}                               // rspReportException ()
}                               // rspReportException ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP continue request
//! Handle a RSP continue request
 
 
//! This version is typically used for the 'c' packet, to continue without
//! This version is typically used for the 'c' packet, to continue without
//! signal, in which case EXCEPT_NONE is passed in as the exception to use.
//! signal, in which case EXCEPT_NONE is passed in as the exception to use.
 
 
//! At present other exceptions are not supported
//! At present other exceptions are not supported
 
 
//! @param[in] except  The OpenRISC 1000 exception to use
//! @param[in] except  The OpenRISC 1000 exception to use
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspContinue(uint32_t except)
void GdbServerSC::rspContinue(uint32_t except)
{
{
        uint32_t addr;          // Address to continue from, if any
        uint32_t addr;          // Address to continue from, if any
 
 
        // Reject all except 'c' packets
        // Reject all except 'c' packets
        if ('c' != pkt->data[0]) {
        if ('c' != pkt->data[0]) {
                cerr <<
                cerr <<
                    "Warning: Continue with signal not currently supported: " <<
                    "Warning: Continue with signal not currently supported: " <<
                    "ignored" << endl;
                    "ignored" << endl;
                return;
                return;
        }
        }
        // Get an address if we have one
        // Get an address if we have one
        if (0 == strcmp("c", pkt->data)) {
        if (0 == strcmp("c", pkt->data)) {
                addr = readNpc();       // Default uses current NPC
                addr = readNpc();       // Default uses current NPC
        } else if (1 != sscanf(pkt->data, "c%lx", &addr)) {
        } else if (1 != sscanf(pkt->data, "c%lx", &addr)) {
                cerr << "Warning: RSP continue address " << pkt->data
                cerr << "Warning: RSP continue address " << pkt->data
                    << " not recognized: ignored" << endl;
                    << " not recognized: ignored" << endl;
                addr = readNpc();       // Default uses current NPC
                addr = readNpc();       // Default uses current NPC
        }
        }
 
 
        rspContinue(addr, EXCEPT_NONE);
        rspContinue(addr, EXCEPT_NONE);
 
 
}                               // rspContinue ()
}                               // rspContinue ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP continue with signal request
//! Handle a RSP continue with signal request
 
 
//! @todo Currently does nothing. Will use the underlying generic continue
//! @todo Currently does nothing. Will use the underlying generic continue
//!       function. 
//!       function. 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspContinue()
void GdbServerSC::rspContinue()
{
{
        cerr << "RSP continue with signal '" << pkt->data
        cerr << "RSP continue with signal '" << pkt->data
            << "' received" << endl;
            << "' received" << endl;
 
 
}                               // rspContinue ()
}                               // rspContinue ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Generic processing of a continue request
//! Generic processing of a continue request
 
 
//! The signal may be EXCEPT_NONE if there is no exception to be
//! The signal may be EXCEPT_NONE if there is no exception to be
//! handled. Currently the exception is ignored.
//! handled. Currently the exception is ignored.
 
 
//! The single step flag is cleared in the debug registers and then the
//! The single step flag is cleared in the debug registers and then the
//! processor is unstalled.
//! processor is unstalled.
 
 
//! @param[in] addr    Address from which to step
//! @param[in] addr    Address from which to step
//! @param[in] except  The exception to use (if any)                         
//! @param[in] except  The exception to use (if any)                         
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspContinue(uint32_t addr, uint32_t except)
void GdbServerSC::rspContinue(uint32_t addr, uint32_t except)
{
{
        // Set the address as the value of the next program counter
        // Set the address as the value of the next program counter
        writeNpc(addr);
        writeNpc(addr);
 
 
        /*
        /*
           // If we're continuing from a breakpoint, replace that instruction in the memory
           // If we're continuing from a breakpoint, replace that instruction in the memory
           // ... actually no, I was wrong about this.
           // ... actually no, I was wrong about this.
           if (NULL != mpHash->lookup (BP_MEMORY, addr) && rsp_sigval == TARGET_SIGNAL_TRAP)
           if (NULL != mpHash->lookup (BP_MEMORY, addr) && rsp_sigval == TARGET_SIGNAL_TRAP)
           {
           {
           MpEntry *entry = mpHash->lookup (BP_MEMORY, addr);
           MpEntry *entry = mpHash->lookup (BP_MEMORY, addr);
           debugUnit->writeMem32(entry->addr, entry->instr);
           debugUnit->writeMem32(entry->addr, entry->instr);
           }
           }
         */
         */
 
 
        // Clear Debug Reason Register and watchpoint break generation in Debug Mode
        // Clear Debug Reason Register and watchpoint break generation in Debug Mode
        // Register 2 for watchpoints that we triggered to stop this time.
        // Register 2 for watchpoints that we triggered to stop this time.
        debugUnit->writeSpr(SPR_DRR, 0);
        debugUnit->writeSpr(SPR_DRR, 0);
        if (rsp_sigval == TARGET_SIGNAL_TRAP) {
        if (rsp_sigval == TARGET_SIGNAL_TRAP) {
                /*
                /*
                   Disable last trap generation on watchpoint if this is why we stopped
                   Disable last trap generation on watchpoint if this is why we stopped
                   last time.
                   last time.
                 */
                 */
                uint32_t temp_dmr2 = debugUnit->readSpr(SPR_DMR2);
                uint32_t temp_dmr2 = debugUnit->readSpr(SPR_DMR2);
                if (temp_dmr2 & SPR_DMR2_WBS) {
                if (temp_dmr2 & SPR_DMR2_WBS) {
                        /*
                        /*
                           One of these breakpoints is responsible for our stopping, so
                           One of these breakpoints is responsible for our stopping, so
                           disable it this time we start. GDB will send a packet re-enabling
                           disable it this time we start. GDB will send a packet re-enabling
                           it next time we continue.
                           it next time we continue.
                         */
                         */
                        debugUnit->writeSpr(SPR_DMR2,
                        debugUnit->writeSpr(SPR_DMR2,
                                            temp_dmr2 &
                                            temp_dmr2 &
                                            ~((temp_dmr2 & SPR_DMR2_WBS) >>
                                            ~((temp_dmr2 & SPR_DMR2_WBS) >>
                                              10));
                                              10));
                }
                }
        }
        }
        // Clear the single step trigger in Debug Mode Register 1 and set traps to
        // Clear the single step trigger in Debug Mode Register 1 and set traps to
        // be handled by the debug unit in the Debug Stop Register
        // be handled by the debug unit in the Debug Stop Register
        debugUnit->andSpr(SPR_DMR1, ~SPR_DMR1_ST);
        debugUnit->andSpr(SPR_DMR1, ~SPR_DMR1_ST);
        debugUnit->orSpr(SPR_DSR, SPR_DSR_TE);
        debugUnit->orSpr(SPR_DSR, SPR_DSR_TE);
 
 
        // Unstall the processor. Note the GDB client is now waiting for a reply,
        // Unstall the processor. Note the GDB client is now waiting for a reply,
        // which it will get as soon as the processor stalls again.
        // which it will get as soon as the processor stalls again.
        debugUnit->unstall();
        debugUnit->unstall();
        targetStopped = false;
        targetStopped = false;
 
 
}                               // rspContinue ()
}                               // rspContinue ()
 
 
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//!Handle an interrupt from GDB
//!Handle an interrupt from GDB
 
 
//! Detect an interrupt from GDB and stall the processor                        
//! Detect an interrupt from GDB and stall the processor                        
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void GdbServerSC::rspInterrupt()
void GdbServerSC::rspInterrupt()
{
{
        unsigned char c;
        unsigned char c;
 
 
        c = rsp->getRspChar();
        c = rsp->getRspChar();
        if (c < 0) {
        if (c < 0) {
                // Had issues, just return
                // Had issues, just return
                return;
                return;
        }
        }
        // Ensure this is a ETX control char (0x3), currently, we only call this
        // Ensure this is a ETX control char (0x3), currently, we only call this
        // function when we've peeked and seen it, otherwise, ignore, return and pray
        // function when we've peeked and seen it, otherwise, ignore, return and pray
        // things go back to normal...
        // things go back to normal...
        if (c != 0x03) {
        if (c != 0x03) {
                cerr <<
                cerr <<
                    "* Warning: Interrupt character expected but not found on socket"
                    "* Warning: Interrupt character expected but not found on socket"
                    << endl;
                    << endl;
                return;
                return;
        }
        }
        // Otherwise, it's an interrupt packet, stall the processor, and upon return
        // Otherwise, it's an interrupt packet, stall the processor, and upon return
        // to the main handle_rsp() loop, it will inform GDB.
        // to the main handle_rsp() loop, it will inform GDB.
 
 
        debugUnit->stall();
        debugUnit->stall();
 
 
        // Send a stop reply response, manually set rsp.sigval to TARGET_SIGNAL_NONE
        // Send a stop reply response, manually set rsp.sigval to TARGET_SIGNAL_NONE
        rsp_sigval = TARGET_SIGNAL_NONE;
        rsp_sigval = TARGET_SIGNAL_NONE;
        rspReportException();
        rspReportException();
 
 
        return;
        return;
 
 
}
}
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP read all registers request
//! Handle a RSP read all registers request
 
 
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
//! (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
//! (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
//! returned as a sequence of bytes in target endian order.
//! returned as a sequence of bytes in target endian order.
 
 
//! Each byte is packed as a pair of hex digits.                             
//! Each byte is packed as a pair of hex digits.                             
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspReadAllRegs()
void GdbServerSC::rspReadAllRegs()
{
{
        // The GPRs
        // The GPRs
        for (int r = 0; r < max_gprs; r++) {
        for (int r = 0; r < max_gprs; r++) {
                Utils::reg2Hex(readGpr(r), &(pkt->data[r * 8]));
                Utils::reg2Hex(readGpr(r), &(pkt->data[r * 8]));
        }
        }
 
 
        // PPC, NPC and SR
        // PPC, NPC and SR
        Utils::reg2Hex(debugUnit->readSpr(SPR_PPC),
        Utils::reg2Hex(debugUnit->readSpr(SPR_PPC),
                       &(pkt->data[PPC_REGNUM * 8]));
                       &(pkt->data[PPC_REGNUM * 8]));
        Utils::reg2Hex(readNpc(), &(pkt->data[NPC_REGNUM * 8]));
        Utils::reg2Hex(readNpc(), &(pkt->data[NPC_REGNUM * 8]));
        Utils::reg2Hex(debugUnit->readSpr(SPR_SR), &(pkt->data[SR_REGNUM * 8]));
        Utils::reg2Hex(debugUnit->readSpr(SPR_SR), &(pkt->data[SR_REGNUM * 8]));
 
 
        // Finalize the packet and send it
        // Finalize the packet and send it
        pkt->data[NUM_REGS * 8] = 0;
        pkt->data[NUM_REGS * 8] = 0;
        pkt->setLen(NUM_REGS * 8);
        pkt->setLen(NUM_REGS * 8);
        rsp->putPkt(pkt);
        rsp->putPkt(pkt);
 
 
}                               // rspReadAllRegs ()
}                               // rspReadAllRegs ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP write all registers request
//! Handle a RSP write all registers request
 
 
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
//! (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
//! (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
//! supplied as a sequence of bytes in target endian order.
//! supplied as a sequence of bytes in target endian order.
 
 
//! Each byte is packed as a pair of hex digits.
//! Each byte is packed as a pair of hex digits.
 
 
//! @todo There is no error checking at present. Non-hex chars will generate a
//! @todo There is no error checking at present. Non-hex chars will generate a
//!       warning message, but there is no other check that the right amount
//!       warning message, but there is no other check that the right amount
//!       of data is present. The result is always "OK".
//!       of data is present. The result is always "OK".
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspWriteAllRegs()
void GdbServerSC::rspWriteAllRegs()
{
{
        // The GPRs
        // The GPRs
        for (int r = 0; r < max_gprs; r++) {
        for (int r = 0; r < max_gprs; r++) {
                writeGpr(r, Utils::hex2Reg(&(pkt->data[r * 8])));
                writeGpr(r, Utils::hex2Reg(&(pkt->data[r * 8])));
        }
        }
 
 
        // PPC, NPC and SR
        // PPC, NPC and SR
        debugUnit->writeSpr(SPR_PPC,
        debugUnit->writeSpr(SPR_PPC,
                            Utils::hex2Reg(&(pkt->data[PPC_REGNUM * 8])));
                            Utils::hex2Reg(&(pkt->data[PPC_REGNUM * 8])));
        debugUnit->writeSpr(SPR_SR,
        debugUnit->writeSpr(SPR_SR,
                            Utils::hex2Reg(&(pkt->data[SR_REGNUM * 8])));
                            Utils::hex2Reg(&(pkt->data[SR_REGNUM * 8])));
        writeNpc(Utils::hex2Reg(&(pkt->data[NPC_REGNUM * 8])));
        writeNpc(Utils::hex2Reg(&(pkt->data[NPC_REGNUM * 8])));
 
 
        // Acknowledge (always OK for now).
        // Acknowledge (always OK for now).
        pkt->packStr("OK");
        pkt->packStr("OK");
        rsp->putPkt(pkt);
        rsp->putPkt(pkt);
 
 
}                               // rspWriteAllRegs ()
}                               // rspWriteAllRegs ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP read memory (symbolic) request
//! Handle a RSP read memory (symbolic) request
 
 
//! Syntax is:
//! Syntax is:
 
 
//!   m<addr>,<length>:
//!   m<addr>,<length>:
 
 
//! The response is the bytes, lowest address first, encoded as pairs of hex
//! The response is the bytes, lowest address first, encoded as pairs of hex
//! digits.
//! digits.
 
 
//! The length given is the number of bytes to be read.
//! The length given is the number of bytes to be read.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspReadMem()
void GdbServerSC::rspReadMem()
{
{
        unsigned int addr;      // Where to read the memory
        unsigned int addr;      // Where to read the memory
        int len;                // Number of bytes to read
        int len;                // Number of bytes to read
        int off;                // Offset into the memory
        int off;                // Offset into the memory
 
 
        if (2 != sscanf(pkt->data, "m%x,%x:", &addr, &len)) {
        if (2 != sscanf(pkt->data, "m%x,%x:", &addr, &len)) {
                cerr << "Warning: Failed to recognize RSP read memory command: "
                cerr << "Warning: Failed to recognize RSP read memory command: "
                    << pkt->data << endl;
                    << pkt->data << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
        // Make sure we won't overflow the buffer (2 chars per byte)
        // Make sure we won't overflow the buffer (2 chars per byte)
        if ((len * 2) >= pkt->getBufSize()) {
        if ((len * 2) >= pkt->getBufSize()) {
                cerr << "Warning: Memory read " << pkt->data
                cerr << "Warning: Memory read " << pkt->data
                    << " too large for RSP packet: truncated" << endl;
                    << " too large for RSP packet: truncated" << endl;
                len = (pkt->getBufSize() - 1) / 2;
                len = (pkt->getBufSize() - 1) / 2;
        }
        }
        //cerr << "rspReadMem: " << len << " bytes@0x"<< hex << addr << endl;
        //cerr << "rspReadMem: " << len << " bytes@0x"<< hex << addr << endl;
        // Refill the buffer with the reply
        // Refill the buffer with the reply
        for (off = 0; off < len; off++) {
        for (off = 0; off < len; off++) {
                unsigned char ch = debugUnit->readMem8(addr + off);
                unsigned char ch = debugUnit->readMem8(addr + off);
 
 
                pkt->data[off * 2] = Utils::hex2Char(ch >> 4);
                pkt->data[off * 2] = Utils::hex2Char(ch >> 4);
                pkt->data[off * 2 + 1] = Utils::hex2Char(ch & 0xf);
                pkt->data[off * 2 + 1] = Utils::hex2Char(ch & 0xf);
        }
        }
 
 
        pkt->data[off * 2] = '\0';      // End of string
        pkt->data[off * 2] = '\0';      // End of string
        pkt->setLen(strlen(pkt->data));
        pkt->setLen(strlen(pkt->data));
        rsp->putPkt(pkt);
        rsp->putPkt(pkt);
 
 
}                               // rsp_read_mem ()
}                               // rsp_read_mem ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP write memory (symbolic) request
//! Handle a RSP write memory (symbolic) request
 
 
//! Syntax is:
//! Syntax is:
 
 
//!   m<addr>,<length>:<data>
//!   m<addr>,<length>:<data>
 
 
//! The data is the bytes, lowest address first, encoded as pairs of hex
//! The data is the bytes, lowest address first, encoded as pairs of hex
//! digits.
//! digits.
 
 
//! The length given is the number of bytes to be written.
//! The length given is the number of bytes to be written.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspWriteMem()
void GdbServerSC::rspWriteMem()
{
{
        uint32_t addr;          // Where to write the memory
        uint32_t addr;          // Where to write the memory
        int len;                // Number of bytes to write
        int len;                // Number of bytes to write
 
 
        if (2 != sscanf(pkt->data, "M%x,%x:", &addr, &len)) {
        if (2 != sscanf(pkt->data, "M%x,%x:", &addr, &len)) {
                cerr << "Warning: Failed to recognize RSP write memory "
                cerr << "Warning: Failed to recognize RSP write memory "
                    << pkt->data << endl;
                    << pkt->data << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
        // Find the start of the data and check there is the amount we expect.
        // Find the start of the data and check there is the amount we expect.
        char *symDat = (char *)(memchr(pkt->data, ':', pkt->getBufSize())) + 1;
        char *symDat = (char *)(memchr(pkt->data, ':', pkt->getBufSize())) + 1;
        int datLen = pkt->getLen() - (symDat - pkt->data);
        int datLen = pkt->getLen() - (symDat - pkt->data);
 
 
        // Sanity check
        // Sanity check
        if (len * 2 != datLen) {
        if (len * 2 != datLen) {
                cerr << "Warning: Write of " << len *
                cerr << "Warning: Write of " << len *
                    2 << "digits requested, but " << datLen <<
                    2 << "digits requested, but " << datLen <<
                    " digits supplied: packet ignored" << endl;
                    " digits supplied: packet ignored" << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
        // Write the bytes to memory (no check the address is OK here)
        // Write the bytes to memory (no check the address is OK here)
        for (int off = 0; off < len; off++) {
        for (int off = 0; off < len; off++) {
                uint8_t nyb1 = Utils::char2Hex(symDat[off * 2]);
                uint8_t nyb1 = Utils::char2Hex(symDat[off * 2]);
                uint8_t nyb2 = Utils::char2Hex(symDat[off * 2 + 1]);
                uint8_t nyb2 = Utils::char2Hex(symDat[off * 2 + 1]);
 
 
                if (!debugUnit->writeMem8(addr + off, (nyb1 << 4) | nyb2)) {
                if (!debugUnit->writeMem8(addr + off, (nyb1 << 4) | nyb2)) {
                        pkt->packStr("E01");
                        pkt->packStr("E01");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
        }
        }
 
 
        pkt->packStr("OK");
        pkt->packStr("OK");
        rsp->putPkt(pkt);
        rsp->putPkt(pkt);
 
 
}                               // rspWriteMem ()
}                               // rspWriteMem ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Read a single register
//! Read a single register
 
 
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
//! (i.e. SPR NPC) and SR (i.e. SPR SR). The register is returned as a
//! (i.e. SPR NPC) and SR (i.e. SPR SR). The register is returned as a
//! sequence of bytes in target endian order.
//! sequence of bytes in target endian order.
 
 
//! Each byte is packed as a pair of hex digits.
//! Each byte is packed as a pair of hex digits.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspReadReg()
void GdbServerSC::rspReadReg()
{
{
        unsigned int regNum;
        unsigned int regNum;
 
 
        // Break out the fields from the data
        // Break out the fields from the data
        if (1 != sscanf(pkt->data, "p%x", &regNum)) {
        if (1 != sscanf(pkt->data, "p%x", &regNum)) {
                cerr <<
                cerr <<
                    "Warning: Failed to recognize RSP read register command: "
                    "Warning: Failed to recognize RSP read register command: "
                    << pkt->data << endl;
                    << pkt->data << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
        // Get the relevant register
        // Get the relevant register
        if (regNum < max_gprs) {
        if (regNum < max_gprs) {
                Utils::Utils::reg2Hex(readGpr(regNum), pkt->data);
                Utils::Utils::reg2Hex(readGpr(regNum), pkt->data);
        } else if (PPC_REGNUM == regNum) {
        } else if (PPC_REGNUM == regNum) {
                Utils::Utils::reg2Hex(debugUnit->readSpr(SPR_PPC), pkt->data);
                Utils::Utils::reg2Hex(debugUnit->readSpr(SPR_PPC), pkt->data);
        } else if (NPC_REGNUM == regNum) {
        } else if (NPC_REGNUM == regNum) {
                Utils::Utils::reg2Hex(readNpc(), pkt->data);
                Utils::Utils::reg2Hex(readNpc(), pkt->data);
        } else if (SR_REGNUM == regNum) {
        } else if (SR_REGNUM == regNum) {
                Utils::Utils::reg2Hex(debugUnit->readSpr(SPR_SR), pkt->data);
                Utils::Utils::reg2Hex(debugUnit->readSpr(SPR_SR), pkt->data);
        } else {
        } else {
                // Error response if we don't know the register
                // Error response if we don't know the register
                cerr << "Warning: Attempt to read unknown register" << regNum
                cerr << "Warning: Attempt to read unknown register" << regNum
                    << ": ignored" << endl;
                    << ": ignored" << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
 
 
        pkt->setLen(strlen(pkt->data));
        pkt->setLen(strlen(pkt->data));
        rsp->putPkt(pkt);
        rsp->putPkt(pkt);
 
 
}                               // rspWriteReg ()
}                               // rspWriteReg ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Write a single register
//! Write a single register
 
 
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
//! (i.e. SPR NPC) and SR (i.e. SPR SR). The register is specified as a
//! (i.e. SPR NPC) and SR (i.e. SPR SR). The register is specified as a
//! sequence of bytes in target endian order.
//! sequence of bytes in target endian order.
 
 
//! Each byte is packed as a pair of hex digits.
//! Each byte is packed as a pair of hex digits.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspWriteReg()
void GdbServerSC::rspWriteReg()
{
{
        unsigned int regNum;
        unsigned int regNum;
        char valstr[9];         // Allow for EOS on the string
        char valstr[9];         // Allow for EOS on the string
 
 
        // Break out the fields from the data
        // Break out the fields from the data
        if (2 != sscanf(pkt->data, "P%x=%8s", &regNum, valstr)) {
        if (2 != sscanf(pkt->data, "P%x=%8s", &regNum, valstr)) {
                cerr <<
                cerr <<
                    "Warning: Failed to recognize RSP write register command "
                    "Warning: Failed to recognize RSP write register command "
                    << pkt->data << endl;
                    << pkt->data << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
        // Set the relevant register
        // Set the relevant register
        if (regNum < max_gprs) {
        if (regNum < max_gprs) {
                writeGpr(regNum, Utils::hex2Reg(valstr));
                writeGpr(regNum, Utils::hex2Reg(valstr));
        } else if (PPC_REGNUM == regNum) {
        } else if (PPC_REGNUM == regNum) {
                debugUnit->writeSpr(SPR_PPC, Utils::hex2Reg(valstr));
                debugUnit->writeSpr(SPR_PPC, Utils::hex2Reg(valstr));
        } else if (NPC_REGNUM == regNum) {
        } else if (NPC_REGNUM == regNum) {
                writeNpc(Utils::hex2Reg(valstr));
                writeNpc(Utils::hex2Reg(valstr));
        } else if (SR_REGNUM == regNum) {
        } else if (SR_REGNUM == regNum) {
                debugUnit->writeSpr(SPR_SR, Utils::hex2Reg(valstr));
                debugUnit->writeSpr(SPR_SR, Utils::hex2Reg(valstr));
        } else {
        } else {
                // Error response if we don't know the register
                // Error response if we don't know the register
                cerr << "Warning: Attempt to write unknown register " << regNum
                cerr << "Warning: Attempt to write unknown register " << regNum
                    << ": ignored" << endl;
                    << ": ignored" << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
 
 
        pkt->packStr("OK");
        pkt->packStr("OK");
        rsp->putPkt(pkt);
        rsp->putPkt(pkt);
 
 
}                               // rspWriteReg ()
}                               // rspWriteReg ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP query request
//! Handle a RSP query request
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspQuery()
void GdbServerSC::rspQuery()
{
{
        if (0 == strcmp("qAttached", pkt->data)) {
        if (0 == strcmp("qAttached", pkt->data)) {
                // We are always attaching to an existing process with the bare metal
                // We are always attaching to an existing process with the bare metal
                // embedded system. 
                // embedded system. 
                pkt->packStr("1");
                pkt->packStr("1");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strcmp("qC", pkt->data)) {
        } else if (0 == strcmp("qC", pkt->data)) {
                // Return the current thread ID (unsigned hex). A null response
                // Return the current thread ID (unsigned hex). A null response
                // indicates to use the previously selected thread. We use the constant
                // indicates to use the previously selected thread. We use the constant
                // OR1KSIM_TID to represent our single thread of control.
                // OR1KSIM_TID to represent our single thread of control.
                sprintf(pkt->data, "QC%x", OR1KSIM_TID);
                sprintf(pkt->data, "QC%x", OR1KSIM_TID);
                pkt->setLen(strlen(pkt->data));
                pkt->setLen(strlen(pkt->data));
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strncmp("qCRC", pkt->data, strlen("qCRC"))) {
        } else if (0 == strncmp("qCRC", pkt->data, strlen("qCRC"))) {
                // Return CRC of memory area
                // Return CRC of memory area
                cerr << "Warning: RSP CRC query not supported" << endl;
                cerr << "Warning: RSP CRC query not supported" << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strcmp("qfThreadInfo", pkt->data)) {
        } else if (0 == strcmp("qfThreadInfo", pkt->data)) {
                // Return info about active threads. We return just the constant
                // Return info about active threads. We return just the constant
                // OR1KSIM_TID to represent our single thread of control.
                // OR1KSIM_TID to represent our single thread of control.
                sprintf(pkt->data, "m%x", OR1KSIM_TID);
                sprintf(pkt->data, "m%x", OR1KSIM_TID);
                pkt->setLen(strlen(pkt->data));
                pkt->setLen(strlen(pkt->data));
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strcmp("qsThreadInfo", pkt->data)) {
        } else if (0 == strcmp("qsThreadInfo", pkt->data)) {
                // Return info about more active threads. We have no more, so return the
                // Return info about more active threads. We have no more, so return the
                // end of list marker, 'l'
                // end of list marker, 'l'
                pkt->packStr("l");
                pkt->packStr("l");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 ==
        } else if (0 ==
                   strncmp("qGetTLSAddr:", pkt->data, strlen("qGetTLSAddr:"))) {
                   strncmp("qGetTLSAddr:", pkt->data, strlen("qGetTLSAddr:"))) {
                // We don't support this feature
                // We don't support this feature
                pkt->packStr("");
                pkt->packStr("");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strncmp("qL", pkt->data, strlen("qL"))) {
        } else if (0 == strncmp("qL", pkt->data, strlen("qL"))) {
                // Deprecated and replaced by 'qfThreadInfo'
                // Deprecated and replaced by 'qfThreadInfo'
                cerr << "Warning: RSP qL deprecated: no info returned" << endl;
                cerr << "Warning: RSP qL deprecated: no info returned" << endl;
                pkt->packStr("qM001");
                pkt->packStr("qM001");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strcmp("qOffsets", pkt->data)) {
        } else if (0 == strcmp("qOffsets", pkt->data)) {
                // Report any relocation
                // Report any relocation
                pkt->packStr("Text=0;Data=0;Bss=0");
                pkt->packStr("Text=0;Data=0;Bss=0");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strncmp("qP", pkt->data, strlen("qP"))) {
        } else if (0 == strncmp("qP", pkt->data, strlen("qP"))) {
                // Deprecated and replaced by 'qThreadExtraInfo'
                // Deprecated and replaced by 'qThreadExtraInfo'
                cerr << "Warning: RSP qP deprecated: no info returned" << endl;
                cerr << "Warning: RSP qP deprecated: no info returned" << endl;
                pkt->packStr("");
                pkt->packStr("");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strncmp("qRcmd,", pkt->data, strlen("qRcmd,"))) {
        } else if (0 == strncmp("qRcmd,", pkt->data, strlen("qRcmd,"))) {
                // This is used to interface to commands to do "stuff"
                // This is used to interface to commands to do "stuff"
                rspCommand();
                rspCommand();
        } else if (0 == strncmp("qSupported", pkt->data, strlen("qSupported"))) {
        } else if (0 == strncmp("qSupported", pkt->data, strlen("qSupported"))) {
                // Report a list of the features we support. For now we just ignore any
                // Report a list of the features we support. For now we just ignore any
                // supplied specific feature queries, but in the future these may be
                // supplied specific feature queries, but in the future these may be
                // supported as well. Note that the packet size allows for 'G' + all the
                // supported as well. Note that the packet size allows for 'G' + all the
                // registers sent to us, or a reply to 'g' with all the registers and an
                // registers sent to us, or a reply to 'g' with all the registers and an
                // EOS so the buffer is a well formed string.
                // EOS so the buffer is a well formed string.
                sprintf(pkt->data, "PacketSize=%x", pkt->getBufSize());
                sprintf(pkt->data, "PacketSize=%x", pkt->getBufSize());
                pkt->setLen(strlen(pkt->data));
                pkt->setLen(strlen(pkt->data));
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strncmp("qSymbol:", pkt->data, strlen("qSymbol:"))) {
        } else if (0 == strncmp("qSymbol:", pkt->data, strlen("qSymbol:"))) {
                // Offer to look up symbols. Nothing we want (for now). TODO. This just
                // Offer to look up symbols. Nothing we want (for now). TODO. This just
                // ignores any replies to symbols we looked up, but we didn't want to
                // ignores any replies to symbols we looked up, but we didn't want to
                // do that anyway!
                // do that anyway!
                pkt->packStr("OK");
                pkt->packStr("OK");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strncmp("qThreadExtraInfo,", pkt->data,
        } else if (0 == strncmp("qThreadExtraInfo,", pkt->data,
                                strlen("qThreadExtraInfo,"))) {
                                strlen("qThreadExtraInfo,"))) {
                // Report that we are runnable, but the text must be hex ASCI
                // Report that we are runnable, but the text must be hex ASCI
                // digits. For now do this by steam, reusing the original packet
                // digits. For now do this by steam, reusing the original packet
                sprintf(pkt->data, "%02x%02x%02x%02x%02x%02x%02x%02x%02x",
                sprintf(pkt->data, "%02x%02x%02x%02x%02x%02x%02x%02x%02x",
                        'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0);
                        'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0);
                pkt->setLen(strlen(pkt->data));
                pkt->setLen(strlen(pkt->data));
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strncmp("qTStatus", pkt->data, strlen("qTstatus"))) {
        } else if (0 == strncmp("qTStatus", pkt->data, strlen("qTstatus"))) {
                // We don't support tracing, return empty packet
                // We don't support tracing, return empty packet
                pkt->packStr("");
                pkt->packStr("");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strncmp("qXfer:", pkt->data, strlen("qXfer:"))) {
        } else if (0 == strncmp("qXfer:", pkt->data, strlen("qXfer:"))) {
                // For now we support no 'qXfer' requests, but these should not be
                // For now we support no 'qXfer' requests, but these should not be
                // expected, since they were not reported by 'qSupported'
                // expected, since they were not reported by 'qSupported'
                cerr << "Warning: RSP 'qXfer' not supported: ignored" << endl;
                cerr << "Warning: RSP 'qXfer' not supported: ignored" << endl;
                pkt->packStr("");
                pkt->packStr("");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else {
        } else {
                cerr << "Unrecognized RSP query: ignored" << endl;
                cerr << "Unrecognized RSP query: ignored" << endl;
        }
        }
}                               // rspQuery ()
}                               // rspQuery ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP qRcmd request
//! Handle a RSP qRcmd request
 
 
//! The actual command follows the "qRcmd," in ASCII encoded to hex
//! The actual command follows the "qRcmd," in ASCII encoded to hex
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspCommand()
void GdbServerSC::rspCommand()
{
{
        char cmd[RSP_PKT_MAX];
        char cmd[RSP_PKT_MAX];
 
 
        Utils::hex2Ascii(cmd, &(pkt->data[strlen("qRcmd,")]));
        Utils::hex2Ascii(cmd, &(pkt->data[strlen("qRcmd,")]));
 
 
        // Work out which command it is
        // Work out which command it is
        if (0 == strncmp("readspr ", cmd, strlen("readspr"))) {
        if (0 == strncmp("readspr ", cmd, strlen("readspr"))) {
                unsigned int sprNum;
                unsigned int sprNum;
 
 
                // Parse and return error if we fail
                // Parse and return error if we fail
                if (1 != sscanf(cmd, "readspr %4x", &sprNum)) {
                if (1 != sscanf(cmd, "readspr %4x", &sprNum)) {
                        cerr << "Warning: qRcmd " << cmd
                        cerr << "Warning: qRcmd " << cmd
                            << "not recognized: ignored" << endl;
                            << "not recognized: ignored" << endl;
                        pkt->packStr("E01");
                        pkt->packStr("E01");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
                // SPR out of range
                // SPR out of range
                if (sprNum > MAX_SPRS) {
                if (sprNum > MAX_SPRS) {
                        cerr << "Warning: qRcmd readspr " << hex << sprNum
                        cerr << "Warning: qRcmd readspr " << hex << sprNum
                            << dec << " too large: ignored" << endl;
                            << dec << " too large: ignored" << endl;
                        pkt->packStr("E01");
                        pkt->packStr("E01");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
                // Construct the reply
                // Construct the reply
                sprintf(cmd, "%8lx", debugUnit->readSpr(sprNum));
                sprintf(cmd, "%8lx", debugUnit->readSpr(sprNum));
                Utils::ascii2Hex(pkt->data, cmd);
                Utils::ascii2Hex(pkt->data, cmd);
                pkt->setLen(strlen(pkt->data));
                pkt->setLen(strlen(pkt->data));
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if (0 == strncmp("writespr ", cmd, strlen("writespr"))) {
        } else if (0 == strncmp("writespr ", cmd, strlen("writespr"))) {
                unsigned int sprNum;
                unsigned int sprNum;
                uint32_t val;
                uint32_t val;
 
 
                // Parse and return error if we fail
                // Parse and return error if we fail
                if (2 != sscanf(cmd, "writespr %4x %8lx", &sprNum, &val)) {
                if (2 != sscanf(cmd, "writespr %4x %8lx", &sprNum, &val)) {
                        cerr << "Warning: qRcmd " << cmd <<
                        cerr << "Warning: qRcmd " << cmd <<
                            " not recognized: ignored" << endl;
                            " not recognized: ignored" << endl;
                        pkt->packStr("E01");
                        pkt->packStr("E01");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
                // SPR out of range
                // SPR out of range
                if (sprNum > MAX_SPRS) {
                if (sprNum > MAX_SPRS) {
                        cerr << "Warning: qRcmd writespr " << hex << sprNum
                        cerr << "Warning: qRcmd writespr " << hex << sprNum
                            << dec << " too large: ignored" << endl;
                            << dec << " too large: ignored" << endl;
                        pkt->packStr("E01");
                        pkt->packStr("E01");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
                // Update the SPR and reply "OK"
                // Update the SPR and reply "OK"
                debugUnit->writeSpr(sprNum, val);
                debugUnit->writeSpr(sprNum, val);
                pkt->packStr("OK");
                pkt->packStr("OK");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        }
        }
 
 
}                               // rspCommand ()
}                               // rspCommand ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP set request
//! Handle a RSP set request
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspSet()
void GdbServerSC::rspSet()
{
{
        if (0 == strncmp("QPassSignals:", pkt->data, strlen("QPassSignals:"))) {
        if (0 == strncmp("QPassSignals:", pkt->data, strlen("QPassSignals:"))) {
                // Passing signals not supported
                // Passing signals not supported
                pkt->packStr("");
                pkt->packStr("");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else if ((0 == strncmp("QTDP", pkt->data, strlen("QTDP"))) ||
        } else if ((0 == strncmp("QTDP", pkt->data, strlen("QTDP"))) ||
                   (0 == strncmp("QFrame", pkt->data, strlen("QFrame"))) ||
                   (0 == strncmp("QFrame", pkt->data, strlen("QFrame"))) ||
                   (0 == strcmp("QTStart", pkt->data)) ||
                   (0 == strcmp("QTStart", pkt->data)) ||
                   (0 == strcmp("QTStop", pkt->data)) ||
                   (0 == strcmp("QTStop", pkt->data)) ||
                   (0 == strcmp("QTinit", pkt->data)) ||
                   (0 == strcmp("QTinit", pkt->data)) ||
                   (0 == strncmp("QTro", pkt->data, strlen("QTro")))) {
                   (0 == strncmp("QTro", pkt->data, strlen("QTro")))) {
                // All tracepoint features are not supported. This reply is really only
                // All tracepoint features are not supported. This reply is really only
                // needed to 'QTDP', since with that the others should not be
                // needed to 'QTDP', since with that the others should not be
                // generated.
                // generated.
                pkt->packStr("");
                pkt->packStr("");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else {
        } else {
                cerr << "Unrecognized RSP set request: ignored" << endl;
                cerr << "Unrecognized RSP set request: ignored" << endl;
                delete pkt;
                delete pkt;
        }
        }
}                               // rspSet ()
}                               // rspSet ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP restart request
//! Handle a RSP restart request
 
 
//! For now we just put the program counter back to the reset vector. If we
//! For now we just put the program counter back to the reset vector. If we
//! supported the vRun request, we should use the address specified
//! supported the vRun request, we should use the address specified
//! there. There is no point in unstalling the processor, since we'll never
//! there. There is no point in unstalling the processor, since we'll never
//! get control back.
//! get control back.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspRestart()
void GdbServerSC::rspRestart()
{
{
        writeNpc(EXCEPT_RESET);
        writeNpc(EXCEPT_RESET);
 
 
}                               // rspRestart ()
}                               // rspRestart ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP step request
//! Handle a RSP step request
 
 
//! This version is typically used for the 's' packet, to continue without
//! This version is typically used for the 's' packet, to continue without
//! signal, in which case EXCEPT_NONE is passed in as the exception to use.
//! signal, in which case EXCEPT_NONE is passed in as the exception to use.
 
 
//! @param[in] except  The exception to use. Only EXCEPT_NONE should be set
//! @param[in] except  The exception to use. Only EXCEPT_NONE should be set
//!                    this way.
//!                    this way.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspStep(uint32_t except)
void GdbServerSC::rspStep(uint32_t except)
{
{
        uint32_t addr;          // The address to step from, if any
        uint32_t addr;          // The address to step from, if any
 
 
        // Reject all except 's' packets
        // Reject all except 's' packets
        if ('s' != pkt->data[0]) {
        if ('s' != pkt->data[0]) {
                cerr << "Warning: Step with signal not currently supported: "
                cerr << "Warning: Step with signal not currently supported: "
                    << "ignored" << endl;
                    << "ignored" << endl;
                return;
                return;
        }
        }
 
 
        if (0 == strcmp("s", pkt->data)) {
        if (0 == strcmp("s", pkt->data)) {
                addr = readNpc();       // Default uses current NPC
                addr = readNpc();       // Default uses current NPC
        } else if (1 != sscanf(pkt->data, "s%lx", &addr)) {
        } else if (1 != sscanf(pkt->data, "s%lx", &addr)) {
                cerr << "Warning: RSP step address " << pkt->data
                cerr << "Warning: RSP step address " << pkt->data
                    << " not recognized: ignored" << endl;
                    << " not recognized: ignored" << endl;
                addr = readNpc();       // Default uses current NPC
                addr = readNpc();       // Default uses current NPC
        }
        }
 
 
        rspStep(addr, EXCEPT_NONE);
        rspStep(addr, EXCEPT_NONE);
 
 
}                               // rspStep ()
}                               // rspStep ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP step with signal request
//! Handle a RSP step with signal request
 
 
//! @todo Currently null. Will use the underlying generic step function.
//! @todo Currently null. Will use the underlying generic step function.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspStep()
void GdbServerSC::rspStep()
{
{
        cerr << "RSP step with signal '" << pkt->data << "' received" << endl;
        cerr << "RSP step with signal '" << pkt->data << "' received" << endl;
 
 
}                               // rspStep ()
}                               // rspStep ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Generic processing of a step request
//! Generic processing of a step request
 
 
//! The signal may be EXCEPT_NONE if there is no exception to be
//! The signal may be EXCEPT_NONE if there is no exception to be
//! handled. Currently the exception is ignored.
//! handled. Currently the exception is ignored.
 
 
//! The single step flag is set in the debug registers and then the processor
//! The single step flag is set in the debug registers and then the processor
//! is unstalled.
//! is unstalled.
 
 
//! @todo There appears to be a bug in the ORPSoC debug unit, whereby multiple
//! @todo There appears to be a bug in the ORPSoC debug unit, whereby multiple
//!       single steps make a mess of the pipeline, leading to multiple
//!       single steps make a mess of the pipeline, leading to multiple
//!       executions of the same instruction. A fix would be to use l.trap (as
//!       executions of the same instruction. A fix would be to use l.trap (as
//!       for continue) for any consecutive calls to step.
//!       for continue) for any consecutive calls to step.
 
 
//! @param[in] addr    Address from which to step
//! @param[in] addr    Address from which to step
//! @param[in] except  The exception to use (if any)                         
//! @param[in] except  The exception to use (if any)                         
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspStep(uint32_t addr, uint32_t except)
void GdbServerSC::rspStep(uint32_t addr, uint32_t except)
{
{
        // Set the address as the value of the next program counter
        // Set the address as the value of the next program counter
        writeNpc(addr);
        writeNpc(addr);
 
 
        /*
        /*
           // If we're continuing from a breakpoint, replace that instruction in the memory
           // If we're continuing from a breakpoint, replace that instruction in the memory
           // ... actually no, I was wrong about this.
           // ... actually no, I was wrong about this.
           if (NULL != mpHash->lookup (BP_MEMORY, addr) && rsp_sigval == TARGET_SIGNAL_TRAP)
           if (NULL != mpHash->lookup (BP_MEMORY, addr) && rsp_sigval == TARGET_SIGNAL_TRAP)
           {
           {
           MpEntry *entry = mpHash->lookup (BP_MEMORY, addr);
           MpEntry *entry = mpHash->lookup (BP_MEMORY, addr);
           debugUnit->writeMem32(entry->addr, entry->instr);
           debugUnit->writeMem32(entry->addr, entry->instr);
           }
           }
         */
         */
 
 
        // Clear Debug Reason Register and watchpoint break generation in Debug Mode
        // Clear Debug Reason Register and watchpoint break generation in Debug Mode
        // Register 2 for watchpoints that we triggered to stop this time.
        // Register 2 for watchpoints that we triggered to stop this time.
        debugUnit->writeSpr(SPR_DRR, 0);
        debugUnit->writeSpr(SPR_DRR, 0);
        if (rsp_sigval == TARGET_SIGNAL_TRAP) {
        if (rsp_sigval == TARGET_SIGNAL_TRAP) {
                /*
                /*
                   Disable last trap generation on watchpoint if this is why we stopped
                   Disable last trap generation on watchpoint if this is why we stopped
                   last time.
                   last time.
                 */
                 */
                uint32_t temp_dmr2 = debugUnit->readSpr(SPR_DMR2);
                uint32_t temp_dmr2 = debugUnit->readSpr(SPR_DMR2);
                if (temp_dmr2 & SPR_DMR2_WBS) {
                if (temp_dmr2 & SPR_DMR2_WBS) {
                        /*
                        /*
                           One of these breakpoints is responsible for our stopping, so
                           One of these breakpoints is responsible for our stopping, so
                           disable it this time we start. GDB will send a packet re-enabling
                           disable it this time we start. GDB will send a packet re-enabling
                           it next time we continue.
                           it next time we continue.
                         */
                         */
                        debugUnit->writeSpr(SPR_DMR2,
                        debugUnit->writeSpr(SPR_DMR2,
                                            temp_dmr2 &
                                            temp_dmr2 &
                                            ~((temp_dmr2 & SPR_DMR2_WBS) >>
                                            ~((temp_dmr2 & SPR_DMR2_WBS) >>
                                              10));
                                              10));
                }
                }
        }
        }
        // Set the single step trigger in Debug Mode Register 1 and set traps to be
        // Set the single step trigger in Debug Mode Register 1 and set traps to be
        // handled by the debug unit in the Debug Stop Register
        // handled by the debug unit in the Debug Stop Register
        debugUnit->orSpr(SPR_DMR1, SPR_DMR1_ST);
        debugUnit->orSpr(SPR_DMR1, SPR_DMR1_ST);
        debugUnit->orSpr(SPR_DSR, SPR_DSR_TE);
        debugUnit->orSpr(SPR_DSR, SPR_DSR_TE);
 
 
        // Unstall the processor. Note the GDB client is now waiting for a reply,
        // Unstall the processor. Note the GDB client is now waiting for a reply,
        // which it will get as soon as the processor stalls again.
        // which it will get as soon as the processor stalls again.
        debugUnit->unstall();
        debugUnit->unstall();
        targetStopped = false;
        targetStopped = false;
 
 
}                               // rspStep ()
}                               // rspStep ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP 'v' packet
//! Handle a RSP 'v' packet
 
 
//! These are commands associated with executing the code on the target
//! These are commands associated with executing the code on the target
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspVpkt()
void GdbServerSC::rspVpkt()
{
{
        if (0 == strncmp("vAttach;", pkt->data, strlen("vAttach;"))) {
        if (0 == strncmp("vAttach;", pkt->data, strlen("vAttach;"))) {
                // Attaching is a null action, since we have no other process. We just
                // Attaching is a null action, since we have no other process. We just
                // return a stop packet (using TRAP) to indicate we are stopped.
                // return a stop packet (using TRAP) to indicate we are stopped.
                pkt->packStr("S05");
                pkt->packStr("S05");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        } else if (0 == strcmp("vCont?", pkt->data)) {
        } else if (0 == strcmp("vCont?", pkt->data)) {
                // For now we don't support this.
                // For now we don't support this.
                pkt->packStr("");
                pkt->packStr("");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        } else if (0 == strncmp("vCont", pkt->data, strlen("vCont"))) {
        } else if (0 == strncmp("vCont", pkt->data, strlen("vCont"))) {
                // This shouldn't happen, because we've reported non-support via vCont?
                // This shouldn't happen, because we've reported non-support via vCont?
                // above
                // above
                cerr << "Warning: RSP vCont not supported: ignored" << endl;
                cerr << "Warning: RSP vCont not supported: ignored" << endl;
                return;
                return;
        } else if (0 == strncmp("vFile:", pkt->data, strlen("vFile:"))) {
        } else if (0 == strncmp("vFile:", pkt->data, strlen("vFile:"))) {
                // For now we don't support this.
                // For now we don't support this.
                cerr << "Warning: RSP vFile not supported: ignored" << endl;
                cerr << "Warning: RSP vFile not supported: ignored" << endl;
                pkt->packStr("");
                pkt->packStr("");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        } else if (0 ==
        } else if (0 ==
                   strncmp("vFlashErase:", pkt->data, strlen("vFlashErase:"))) {
                   strncmp("vFlashErase:", pkt->data, strlen("vFlashErase:"))) {
                // For now we don't support this.
                // For now we don't support this.
                cerr << "Warning: RSP vFlashErase not supported: ignored" <<
                cerr << "Warning: RSP vFlashErase not supported: ignored" <<
                    endl;
                    endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        } else if (0 ==
        } else if (0 ==
                   strncmp("vFlashWrite:", pkt->data, strlen("vFlashWrite:"))) {
                   strncmp("vFlashWrite:", pkt->data, strlen("vFlashWrite:"))) {
                // For now we don't support this.
                // For now we don't support this.
                cerr << "Warning: RSP vFlashWrite not supported: ignored" <<
                cerr << "Warning: RSP vFlashWrite not supported: ignored" <<
                    endl;
                    endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        } else if (0 == strcmp("vFlashDone", pkt->data)) {
        } else if (0 == strcmp("vFlashDone", pkt->data)) {
                // For now we don't support this.
                // For now we don't support this.
                cerr << "Warning: RSP vFlashDone not supported: ignored" <<
                cerr << "Warning: RSP vFlashDone not supported: ignored" <<
                    endl;;
                    endl;;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        } else if (0 == strncmp("vRun;", pkt->data, strlen("vRun;"))) {
        } else if (0 == strncmp("vRun;", pkt->data, strlen("vRun;"))) {
                // We shouldn't be given any args, but check for this
                // We shouldn't be given any args, but check for this
                if (pkt->getLen() > strlen("vRun;")) {
                if (pkt->getLen() > strlen("vRun;")) {
                        cerr << "Warning: Unexpected arguments to RSP vRun "
                        cerr << "Warning: Unexpected arguments to RSP vRun "
                            "command: ignored" << endl;
                            "command: ignored" << endl;
                }
                }
                // Restart the current program. However unlike a "R" packet, "vRun"
                // Restart the current program. However unlike a "R" packet, "vRun"
                // should behave as though it has just stopped. We use signal 5 (TRAP).
                // should behave as though it has just stopped. We use signal 5 (TRAP).
                rspRestart();
                rspRestart();
                pkt->packStr("S05");
                pkt->packStr("S05");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
        } else {
        } else {
                cerr << "Warning: Unknown RSP 'v' packet type " << pkt->data
                cerr << "Warning: Unknown RSP 'v' packet type " << pkt->data
                    << ": ignored" << endl;
                    << ": ignored" << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
}                               // rspVpkt ()
}                               // rspVpkt ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP write memory (binary) request
//! Handle a RSP write memory (binary) request
 
 
//! Syntax is:
//! Syntax is:
 
 
//!   X<addr>,<length>:
//!   X<addr>,<length>:
 
 
//! Followed by the specified number of bytes as raw binary. Response should be
//! Followed by the specified number of bytes as raw binary. Response should be
//! "OK" if all copied OK, E<nn> if error <nn> has occurred.
//! "OK" if all copied OK, E<nn> if error <nn> has occurred.
 
 
//! The length given is the number of bytes to be written. The data buffer has
//! The length given is the number of bytes to be written. The data buffer has
//! already been unescaped, so will hold this number of bytes.
//! already been unescaped, so will hold this number of bytes.
 
 
//! The data is in model-endian format, so no transformation is needed.
//! The data is in model-endian format, so no transformation is needed.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspWriteMemBin()
void GdbServerSC::rspWriteMemBin()
{
{
        uint32_t addr;          // Where to write the memory
        uint32_t addr;          // Where to write the memory
        int len;                // Number of bytes to write
        int len;                // Number of bytes to write
 
 
        if (2 != sscanf(pkt->data, "X%x,%x:", &addr, &len)) {
        if (2 != sscanf(pkt->data, "X%x,%x:", &addr, &len)) {
                cerr <<
                cerr <<
                    "Warning: Failed to recognize RSP write memory command: %s"
                    "Warning: Failed to recognize RSP write memory command: %s"
                    << pkt->data << endl;
                    << pkt->data << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
        // Find the start of the data and "unescape" it. Bindat must be unsigned, or
        // Find the start of the data and "unescape" it. Bindat must be unsigned, or
        // all sorts of horrible sign extensions will happen when val is computed
        // all sorts of horrible sign extensions will happen when val is computed
        // below!
        // below!
        uint8_t *bindat = (uint8_t *) (memchr(pkt->data, ':',
        uint8_t *bindat = (uint8_t *) (memchr(pkt->data, ':',
                                              pkt->getBufSize())) + 1;
                                              pkt->getBufSize())) + 1;
        int off = (char *)bindat - pkt->data;
        int off = (char *)bindat - pkt->data;
        int newLen = Utils::rspUnescape((char *)bindat, pkt->getLen() - off);
        int newLen = Utils::rspUnescape((char *)bindat, pkt->getLen() - off);
 
 
        // Sanity check
        // Sanity check
        if (newLen != len) {
        if (newLen != len) {
                int minLen = len < newLen ? len : newLen;
                int minLen = len < newLen ? len : newLen;
 
 
                cerr << "Warning: Write of " << len << " bytes requested, but "
                cerr << "Warning: Write of " << len << " bytes requested, but "
                    << newLen << " bytes supplied. " << minLen <<
                    << newLen << " bytes supplied. " << minLen <<
                    " will be written" << endl;
                    " will be written" << endl;
                len = minLen;
                len = minLen;
        }
        }
        // Write the bytes to memory. More efficent to do this in 32-bit chunks
        // Write the bytes to memory. More efficent to do this in 32-bit chunks
        int startBytes = addr & 0x3;
        int startBytes = addr & 0x3;
        int endBytes = (addr + len) & 0x3;
        int endBytes = (addr + len) & 0x3;
 
 
        // First partial word. Access bindat in an endian independent fashion.
        // First partial word. Access bindat in an endian independent fashion.
        for (off = 0; off < startBytes; off++) {
        for (off = 0; off < startBytes; off++) {
                if (!debugUnit->writeMem8(addr + off, bindat[off])) {
                if (!debugUnit->writeMem8(addr + off, bindat[off])) {
                        pkt->packStr("E01");
                        pkt->packStr("E01");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
        }
        }
 
 
        // The bulk as words. Convert to model endian before writing.
        // The bulk as words. Convert to model endian before writing.
        for (off = startBytes; off < len; off += 4) {
        for (off = startBytes; off < len; off += 4) {
                uint32_t val = *((uint32_t *) (&(bindat[off])));
                uint32_t val = *((uint32_t *) (&(bindat[off])));
 
 
                if (!debugUnit->writeMem32(addr + off, Utils::htotl(val))) {
                if (!debugUnit->writeMem32(addr + off, Utils::htotl(val))) {
                        pkt->packStr("E01");
                        pkt->packStr("E01");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
        }
        }
 
 
        // Last partial word. Access bindat in an endian independent fashion.
        // Last partial word. Access bindat in an endian independent fashion.
        for (off = len - endBytes; off < len; off++) {
        for (off = len - endBytes; off < len; off++) {
                uint32_t base = (addr + len) & 0xfffffffc;
                uint32_t base = (addr + len) & 0xfffffffc;
 
 
                if (!debugUnit->writeMem8(base + off, bindat[off])) {
                if (!debugUnit->writeMem8(base + off, bindat[off])) {
                        pkt->packStr("E01");
                        pkt->packStr("E01");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
        }
        }
 
 
        pkt->packStr("OK");
        pkt->packStr("OK");
        rsp->putPkt(pkt);
        rsp->putPkt(pkt);
 
 
}                               // rspWriteMemBin ()
}                               // rspWriteMemBin ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Handle a RSP remove breakpoint or matchpoint request
//! Handle a RSP remove breakpoint or matchpoint request
 
 
//! For now only memory breakpoints are implemented, which are implemented by
//! For now only memory breakpoints are implemented, which are implemented by
//! substituting a breakpoint at the specified address. The implementation must
//! substituting a breakpoint at the specified address. The implementation must
//! cope with the possibility of duplicate packets.
//! cope with the possibility of duplicate packets.
 
 
//! @todo This doesn't work with icache/immu yet
//! @todo This doesn't work with icache/immu yet
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::rspRemoveMatchpoint()
void GdbServerSC::rspRemoveMatchpoint()
{
{
        MpType type;            // What sort of matchpoint
        MpType type;            // What sort of matchpoint
        uint32_t addr;          // Address specified
        uint32_t addr;          // Address specified
        uint32_t instr;         // Instruction value found
        uint32_t instr;         // Instruction value found
        int len;                // Matchpoint length (not used)
        int len;                // Matchpoint length (not used)
 
 
        // Break out the instruction
        // Break out the instruction
        if (3 != sscanf(pkt->data, "z%1d,%lx,%1d", (int *)&type, &addr, &len)) {
        if (3 != sscanf(pkt->data, "z%1d,%lx,%1d", (int *)&type, &addr, &len)) {
                cerr << "Warning: RSP matchpoint deletion request not "
                cerr << "Warning: RSP matchpoint deletion request not "
                    << "recognized: ignored" << endl;
                    << "recognized: ignored" << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
        // Sanity check that the length is 4
        // Sanity check that the length is 4
        if (4 != len) {
        if (4 != len) {
                cerr << "Warning: RSP matchpoint deletion length " << len
                cerr << "Warning: RSP matchpoint deletion length " << len
                    << "not valid: 4 assumed" << endl;
                    << "not valid: 4 assumed" << endl;
                len = 4;
                len = 4;
        }
        }
        // Sort out the type of matchpoint
        // Sort out the type of matchpoint
        switch (type) {
        switch (type) {
        case BP_MEMORY:
        case BP_MEMORY:
                // Memory breakpoint - replace the original instruction.
                // Memory breakpoint - replace the original instruction.
                if (mpHash->remove(type, addr, &instr)) {
                if (mpHash->remove(type, addr, &instr)) {
                        //cerr << "rspRemoveMatchpoint at 0x" << hex << addr << " restoring instruction: 0x" << hex << instr <<endl;
                        //cerr << "rspRemoveMatchpoint at 0x" << hex << addr << " restoring instruction: 0x" << hex << instr <<endl;
                        debugUnit->writeMem32(addr, instr);
                        debugUnit->writeMem32(addr, instr);
                }
                }
 
 
                pkt->packStr("OK");
                pkt->packStr("OK");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
 
 
        case BP_HARDWARE:
        case BP_HARDWARE:
                int off;
                int off;
                for (off = 0; off < 8; off++)
                for (off = 0; off < 8; off++)
                        if ((debugUnit->readSpr(SPR_DCR0 + off) == (0x23)) &&
                        if ((debugUnit->readSpr(SPR_DCR0 + off) == (0x23)) &&
                            (debugUnit->readSpr(SPR_DVR0 + off) == addr))
                            (debugUnit->readSpr(SPR_DVR0 + off) == addr))
                                break;
                                break;
                if (off > 7) {
                if (off > 7) {
                        pkt->packStr("E02");    // Failed ot find breakpoint
                        pkt->packStr("E02");    // Failed ot find breakpoint
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
                // Clear DCR's CT and DVR, WGB bit
                // Clear DCR's CT and DVR, WGB bit
                debugUnit->writeSpr(SPR_DCR0 + off, 0);
                debugUnit->writeSpr(SPR_DCR0 + off, 0);
                debugUnit->writeSpr(SPR_DVR0 + off, 0);
                debugUnit->writeSpr(SPR_DVR0 + off, 0);
                debugUnit->writeSpr(SPR_DMR2,
                debugUnit->writeSpr(SPR_DMR2,
                                    debugUnit->readSpr(SPR_DMR2) & ~((1 << off)
                                    debugUnit->readSpr(SPR_DMR2) & ~((1 << off)
                                                                     <<
                                                                     <<
                                                                     SPR_DMR2_WGB_SHIFT));
                                                                     SPR_DMR2_WGB_SHIFT));
                pkt->packStr("OK");
                pkt->packStr("OK");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
 
 
        case WP_WRITE:
        case WP_WRITE:
                {
                {
                        int off;
                        int off;
                        for (off = 0; off < 8; off++) {
                        for (off = 0; off < 8; off++) {
                                if ((debugUnit->readSpr(SPR_DCR0 + off) ==
                                if ((debugUnit->readSpr(SPR_DCR0 + off) ==
                                     (0x63))
                                     (0x63))
                                    && (debugUnit->readSpr(SPR_DVR0 + off) ==
                                    && (debugUnit->readSpr(SPR_DVR0 + off) ==
                                        addr))
                                        addr))
                                        break;
                                        break;
                        }
                        }
                        if (off > 7) {
                        if (off > 7) {
                                pkt->packStr("E02");    // Failed ot find breakpoint
                                pkt->packStr("E02");    // Failed ot find breakpoint
                                rsp->putPkt(pkt);
                                rsp->putPkt(pkt);
                                return;
                                return;
                        }
                        }
                        // Clear DCR's CT and DVR, WGB bit
                        // Clear DCR's CT and DVR, WGB bit
                        debugUnit->writeSpr(SPR_DCR0 + off, 0);
                        debugUnit->writeSpr(SPR_DCR0 + off, 0);
                        debugUnit->writeSpr(SPR_DVR0 + off, 0);
                        debugUnit->writeSpr(SPR_DVR0 + off, 0);
                        debugUnit->writeSpr(SPR_DMR2,
                        debugUnit->writeSpr(SPR_DMR2,
                                            debugUnit->readSpr(SPR_DMR2) &
                                            debugUnit->readSpr(SPR_DMR2) &
                                            ~((1 << off) <<
                                            ~((1 << off) <<
                                              SPR_DMR2_WGB_SHIFT));
                                              SPR_DMR2_WGB_SHIFT));
                        pkt->packStr("OK");
                        pkt->packStr("OK");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
 
 
        case WP_READ:
        case WP_READ:
                {
                {
                        int off;
                        int off;
                        for (off = 0; off < 8; off++) {
                        for (off = 0; off < 8; off++) {
                                if ((debugUnit->readSpr(SPR_DCR0 + off) ==
                                if ((debugUnit->readSpr(SPR_DCR0 + off) ==
                                     (0x43))
                                     (0x43))
                                    && (debugUnit->readSpr(SPR_DVR0 + off) ==
                                    && (debugUnit->readSpr(SPR_DVR0 + off) ==
                                        addr))
                                        addr))
                                        break;
                                        break;
                        }
                        }
                        if (off > 7) {
                        if (off > 7) {
                                pkt->packStr("E02");    // Failed ot find breakpoint
                                pkt->packStr("E02");    // Failed ot find breakpoint
                                rsp->putPkt(pkt);
                                rsp->putPkt(pkt);
                                return;
                                return;
                        }
                        }
                        // Clear DCR's CT and DVR, WGB bit
                        // Clear DCR's CT and DVR, WGB bit
                        debugUnit->writeSpr(SPR_DCR0 + off, 0);
                        debugUnit->writeSpr(SPR_DCR0 + off, 0);
                        debugUnit->writeSpr(SPR_DVR0 + off, 0);
                        debugUnit->writeSpr(SPR_DVR0 + off, 0);
                        debugUnit->writeSpr(SPR_DMR2,
                        debugUnit->writeSpr(SPR_DMR2,
                                            debugUnit->readSpr(SPR_DMR2) &
                                            debugUnit->readSpr(SPR_DMR2) &
                                            ~((1 << off) <<
                                            ~((1 << off) <<
                                              SPR_DMR2_WGB_SHIFT));
                                              SPR_DMR2_WGB_SHIFT));
                        pkt->packStr("OK");
                        pkt->packStr("OK");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
 
 
        case WP_ACCESS:
        case WP_ACCESS:
                {
                {
                        int off;
                        int off;
                        for (off = 0; off < 8; off++) {
                        for (off = 0; off < 8; off++) {
                                //printf("WP_ACCESS remove check off=%d DCR=0x%.8x DVR=0x%.8x\n",
                                //printf("WP_ACCESS remove check off=%d DCR=0x%.8x DVR=0x%.8x\n",
                                //off,debugUnit->readSpr (SPR_DCR0+off),debugUnit->readSpr (SPR_DVR0+off));
                                //off,debugUnit->readSpr (SPR_DCR0+off),debugUnit->readSpr (SPR_DVR0+off));
                                if ((debugUnit->readSpr(SPR_DCR0 + off) ==
                                if ((debugUnit->readSpr(SPR_DCR0 + off) ==
                                     (0xc3))
                                     (0xc3))
                                    && (debugUnit->readSpr(SPR_DVR0 + off) ==
                                    && (debugUnit->readSpr(SPR_DVR0 + off) ==
                                        addr))
                                        addr))
                                        break;
                                        break;
                        }
                        }
                        if (off > 7) {
                        if (off > 7) {
                                //printf("rspRemoveWatchpoint: WP_ACCESS remove ERROR, regpair %d for 0x%.8x\n",off, addr);
                                //printf("rspRemoveWatchpoint: WP_ACCESS remove ERROR, regpair %d for 0x%.8x\n",off, addr);
                                pkt->packStr("E02");    // Failed ot find breakpoint
                                pkt->packStr("E02");    // Failed ot find breakpoint
                                rsp->putPkt(pkt);
                                rsp->putPkt(pkt);
                                return;
                                return;
                        }
                        }
                        //printf("rspRemoveWatchpoint: WP_ACCESS remove, regpair %d for 0x%.8x\n",off, addr);
                        //printf("rspRemoveWatchpoint: WP_ACCESS remove, regpair %d for 0x%.8x\n",off, addr);
 
 
                        // Clear DCR's CT and DVR, WGB bit
                        // Clear DCR's CT and DVR, WGB bit
                        debugUnit->writeSpr(SPR_DCR0 + off, 0);
                        debugUnit->writeSpr(SPR_DCR0 + off, 0);
                        debugUnit->writeSpr(SPR_DVR0 + off, 0);
                        debugUnit->writeSpr(SPR_DVR0 + off, 0);
                        debugUnit->writeSpr(SPR_DMR2,
                        debugUnit->writeSpr(SPR_DMR2,
                                            debugUnit->readSpr(SPR_DMR2) &
                                            debugUnit->readSpr(SPR_DMR2) &
                                            ~((1 << off) <<
                                            ~((1 << off) <<
                                              SPR_DMR2_WGB_SHIFT));
                                              SPR_DMR2_WGB_SHIFT));
                        pkt->packStr("OK");
                        pkt->packStr("OK");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
        default:
        default:
                cerr << "Warning: RSP matchpoint type " << type
                cerr << "Warning: RSP matchpoint type " << type
                    << " not recognized: ignored" << endl;
                    << " not recognized: ignored" << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
}                               // rspRemoveMatchpoint ()
}                               // rspRemoveMatchpoint ()
 
 
//---------------------------------------------------------------------------*/
//---------------------------------------------------------------------------*/
//! Handle a RSP insert breakpoint or matchpoint request
//! Handle a RSP insert breakpoint or matchpoint request
 
 
//! For now only memory breakpoints are implemented, which are implemented by
//! For now only memory breakpoints are implemented, which are implemented by
//! substituting a breakpoint at the specified address. The implementation must
//! substituting a breakpoint at the specified address. The implementation must
//! cope with the possibility of duplicate packets.
//! cope with the possibility of duplicate packets.
 
 
//! @todo This doesn't work with icache/immu yet
//! @todo This doesn't work with icache/immu yet
//---------------------------------------------------------------------------*/
//---------------------------------------------------------------------------*/
void GdbServerSC::rspInsertMatchpoint()
void GdbServerSC::rspInsertMatchpoint()
{
{
        MpType type;            // What sort of matchpoint
        MpType type;            // What sort of matchpoint
        uint32_t addr;          // Address specified
        uint32_t addr;          // Address specified
        int len;                // Matchpoint length (not used)
        int len;                // Matchpoint length (not used)
 
 
        // Break out the instruction
        // Break out the instruction
        if (3 != sscanf(pkt->data, "Z%1d,%lx,%1d", (int *)&type, &addr, &len)) {
        if (3 != sscanf(pkt->data, "Z%1d,%lx,%1d", (int *)&type, &addr, &len)) {
                cerr << "Warning: RSP matchpoint insertion request not "
                cerr << "Warning: RSP matchpoint insertion request not "
                    << "recognized: ignored" << endl;
                    << "recognized: ignored" << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
        // Sanity check that the length is 4
        // Sanity check that the length is 4
        if (4 != len) {
        if (4 != len) {
                cerr << "Warning: RSP matchpoint insertion length " << len
                cerr << "Warning: RSP matchpoint insertion length " << len
                    << "not valid: 4 assumed" << endl;
                    << "not valid: 4 assumed" << endl;
                len = 4;
                len = 4;
        }
        }
        // Sort out the type of matchpoint
        // Sort out the type of matchpoint
        switch (type) {
        switch (type) {
        case BP_MEMORY:
        case BP_MEMORY:
                // Memory breakpoint - substitute a TRAP instruction
                // Memory breakpoint - substitute a TRAP instruction
                mpHash->add(type, addr, debugUnit->readMem32(addr));
                mpHash->add(type, addr, debugUnit->readMem32(addr));
                debugUnit->writeMem32(addr, OR1K_TRAP_INSTR);
                debugUnit->writeMem32(addr, OR1K_TRAP_INSTR);
                pkt->packStr("OK");
                pkt->packStr("OK");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
 
 
        case BP_HARDWARE:
        case BP_HARDWARE:
                {
                {
                        int off;
                        int off;
                        for (off = 0; off < 8; off++)
                        for (off = 0; off < 8; off++)
                                if (!
                                if (!
                                    (debugUnit->readSpr(SPR_DCR0 + off) &
                                    (debugUnit->readSpr(SPR_DCR0 + off) &
                                     SPR_DCR_CT_MASK))
                                     SPR_DCR_CT_MASK))
                                        break;
                                        break;
                        if (off > 7) {
                        if (off > 7) {
                                pkt->packStr("");       // No room
                                pkt->packStr("");       // No room
                                rsp->putPkt(pkt);
                                rsp->putPkt(pkt);
                                return;
                                return;
                        }
                        }
                        // CC = equal, CT = Instruction fetch EA, set WGB bit
                        // CC = equal, CT = Instruction fetch EA, set WGB bit
                        debugUnit->writeSpr(SPR_DCR0 + off, 0x22);
                        debugUnit->writeSpr(SPR_DCR0 + off, 0x22);
                        debugUnit->writeSpr(SPR_DVR0 + off, addr);
                        debugUnit->writeSpr(SPR_DVR0 + off, addr);
                        debugUnit->writeSpr(SPR_DMR2,
                        debugUnit->writeSpr(SPR_DMR2,
                                            debugUnit->readSpr(SPR_DMR2) |
                                            debugUnit->readSpr(SPR_DMR2) |
                                            ((1 << off) << SPR_DMR2_WGB_SHIFT));
                                            ((1 << off) << SPR_DMR2_WGB_SHIFT));
                        pkt->packStr("OK");
                        pkt->packStr("OK");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
 
 
        case WP_WRITE:
        case WP_WRITE:
                {
                {
                        int off;
                        int off;
                        for (off = 0; off < 8; off++)
                        for (off = 0; off < 8; off++)
                                if (!
                                if (!
                                    (debugUnit->readSpr(SPR_DCR0 + off) &
                                    (debugUnit->readSpr(SPR_DCR0 + off) &
                                     SPR_DCR_CT_MASK))
                                     SPR_DCR_CT_MASK))
                                        break;
                                        break;
                        //printf("rspInsertWatchpoint: WP_WRITE, regpair %d for 0x%.8x\n",off, addr);
                        //printf("rspInsertWatchpoint: WP_WRITE, regpair %d for 0x%.8x\n",off, addr);
                        if (off > 7) {
                        if (off > 7) {
                                pkt->packStr("");       // No room
                                pkt->packStr("");       // No room
                                rsp->putPkt(pkt);
                                rsp->putPkt(pkt);
                                return;
                                return;
                        }
                        }
                        // CC = equal, CT = Store EA, set WGB bit
                        // CC = equal, CT = Store EA, set WGB bit
                        debugUnit->writeSpr(SPR_DCR0 + off, 0x62);
                        debugUnit->writeSpr(SPR_DCR0 + off, 0x62);
                        debugUnit->writeSpr(SPR_DVR0 + off, addr);
                        debugUnit->writeSpr(SPR_DVR0 + off, addr);
                        debugUnit->writeSpr(SPR_DMR2,
                        debugUnit->writeSpr(SPR_DMR2,
                                            debugUnit->readSpr(SPR_DMR2) |
                                            debugUnit->readSpr(SPR_DMR2) |
                                            ((1 << off) << SPR_DMR2_WGB_SHIFT));
                                            ((1 << off) << SPR_DMR2_WGB_SHIFT));
                        pkt->packStr("OK");
                        pkt->packStr("OK");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
 
 
        case WP_READ:
        case WP_READ:
                {
                {
                        int off;
                        int off;
                        for (off = 0; off < 8; off++)
                        for (off = 0; off < 8; off++)
                                if (!
                                if (!
                                    (debugUnit->readSpr(SPR_DCR0 + off) &
                                    (debugUnit->readSpr(SPR_DCR0 + off) &
                                     SPR_DCR_CT_MASK))
                                     SPR_DCR_CT_MASK))
                                        break;
                                        break;
                        //printf("rspInsertWatchpoint: WP_WRITE, regpair %d for 0x%.8x\n",off, addr);
                        //printf("rspInsertWatchpoint: WP_WRITE, regpair %d for 0x%.8x\n",off, addr);
                        if (off > 7) {
                        if (off > 7) {
                                pkt->packStr("");       // No room
                                pkt->packStr("");       // No room
                                rsp->putPkt(pkt);
                                rsp->putPkt(pkt);
                                return;
                                return;
                        }
                        }
                        // CC = equal, CT = Load EA, set WGB bit
                        // CC = equal, CT = Load EA, set WGB bit
                        debugUnit->writeSpr(SPR_DCR0 + off, 0x42);
                        debugUnit->writeSpr(SPR_DCR0 + off, 0x42);
                        debugUnit->writeSpr(SPR_DVR0 + off, addr);
                        debugUnit->writeSpr(SPR_DVR0 + off, addr);
                        debugUnit->writeSpr(SPR_DMR2,
                        debugUnit->writeSpr(SPR_DMR2,
                                            debugUnit->readSpr(SPR_DMR2) |
                                            debugUnit->readSpr(SPR_DMR2) |
                                            ((1 << off) << SPR_DMR2_WGB_SHIFT));
                                            ((1 << off) << SPR_DMR2_WGB_SHIFT));
                        pkt->packStr("OK");
                        pkt->packStr("OK");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
 
 
                pkt->packStr("");       // Not supported
                pkt->packStr("");       // Not supported
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
 
 
        case WP_ACCESS:
        case WP_ACCESS:
                {
                {
                        int off;
                        int off;
                        for (off = 0; off < 8; off++)
                        for (off = 0; off < 8; off++)
                                if (!
                                if (!
                                    (debugUnit->readSpr(SPR_DCR0 + off) &
                                    (debugUnit->readSpr(SPR_DCR0 + off) &
                                     SPR_DCR_CT_MASK))
                                     SPR_DCR_CT_MASK))
                                        break;
                                        break;
                        //printf("rspInsertWatchpoint: WP_ACCESS, regpair %d for 0x%.8x\n",off, addr);
                        //printf("rspInsertWatchpoint: WP_ACCESS, regpair %d for 0x%.8x\n",off, addr);
                        if (off > 7) {
                        if (off > 7) {
                                pkt->packStr("");       // No room
                                pkt->packStr("");       // No room
                                rsp->putPkt(pkt);
                                rsp->putPkt(pkt);
                                return;
                                return;
                        }
                        }
                        // CC = equal, CT = Load/Store EA, set WGB bit
                        // CC = equal, CT = Load/Store EA, set WGB bit
                        debugUnit->writeSpr(SPR_DCR0 + off, 0xc2);
                        debugUnit->writeSpr(SPR_DCR0 + off, 0xc2);
                        debugUnit->writeSpr(SPR_DVR0 + off, addr);
                        debugUnit->writeSpr(SPR_DVR0 + off, addr);
                        debugUnit->writeSpr(SPR_DMR2,
                        debugUnit->writeSpr(SPR_DMR2,
                                            debugUnit->readSpr(SPR_DMR2) |
                                            debugUnit->readSpr(SPR_DMR2) |
                                            ((1 << off) << SPR_DMR2_WGB_SHIFT));
                                            ((1 << off) << SPR_DMR2_WGB_SHIFT));
                        pkt->packStr("OK");
                        pkt->packStr("OK");
                        rsp->putPkt(pkt);
                        rsp->putPkt(pkt);
                        return;
                        return;
                }
                }
 
 
        default:
        default:
                cerr << "Warning: RSP matchpoint type " << type
                cerr << "Warning: RSP matchpoint type " << type
                    << "not recognized: ignored" << endl;
                    << "not recognized: ignored" << endl;
                pkt->packStr("E01");
                pkt->packStr("E01");
                rsp->putPkt(pkt);
                rsp->putPkt(pkt);
                return;
                return;
        }
        }
}                               // rspInsertMatchpoint ()
}                               // rspInsertMatchpoint ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Read the value of the Next Program Counter (a SPR)
//! Read the value of the Next Program Counter (a SPR)
 
 
//! A convenience routine.
//! A convenience routine.
 
 
//! Setting the NPC flushes the pipeline, so subsequent reads will return
//! Setting the NPC flushes the pipeline, so subsequent reads will return
//! zero until the processor has refilled the pipeline. This will not be
//! zero until the processor has refilled the pipeline. This will not be
//! happening if the processor is stalled (as it is when GDB had control).
//! happening if the processor is stalled (as it is when GDB had control).
 
 
//! However for debugging we always want to know what the effective value of
//! However for debugging we always want to know what the effective value of
//! the NPC will be (i.e. the value that will be used once the pipeline has
//! the NPC will be (i.e. the value that will be used once the pipeline has
//! refilled). Fortunately SPR cacheing in the debug unit silently solves this
//! refilled). Fortunately SPR cacheing in the debug unit silently solves this
//! for us.
//! for us.
 
 
//! @return  The value of the NPC
//! @return  The value of the NPC
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
uint32_t GdbServerSC::readNpc()
uint32_t GdbServerSC::readNpc()
{
{
        return debugUnit->readSpr(SPR_NPC);
        return debugUnit->readSpr(SPR_NPC);
 
 
}                               // readNpc ()
}                               // readNpc ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Write the value of the Next Program Counter (a SPR)
//! Write the value of the Next Program Counter (a SPR)
 
 
//! A convenience function.
//! A convenience function.
 
 
//! Setting the NPC flushes the pipeline, so subsequent reads will return
//! Setting the NPC flushes the pipeline, so subsequent reads will return
//! zero until the processor has refilled the pipeline. This will not be
//! zero until the processor has refilled the pipeline. This will not be
//! happening if the processor is stalled (as it is when GDB had control).
//! happening if the processor is stalled (as it is when GDB had control).
 
 
//! However for debugging we always want to know what the effective value of
//! However for debugging we always want to know what the effective value of
//! the NPC will be (i.e. the value that will be used once the pipeline has
//! the NPC will be (i.e. the value that will be used once the pipeline has
//! refilled). Fortunately SPR cacheing in the debug unit silently solves this
//! refilled). Fortunately SPR cacheing in the debug unit silently solves this
//! for us.
//! for us.
 
 
//! There is one other caveat for the NPC. We do not wish to write it (whether
//! There is one other caveat for the NPC. We do not wish to write it (whether
//! or not it is cached) if it has not changed. So unlike all other SPRs we
//! or not it is cached) if it has not changed. So unlike all other SPRs we
//! always read it first before writing.
//! always read it first before writing.
 
 
//! @param[in]  The address to write into the NPC
//! @param[in]  The address to write into the NPC
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::writeNpc(uint32_t addr)
void GdbServerSC::writeNpc(uint32_t addr)
{
{
        if (addr != readNpc()) {
        if (addr != readNpc()) {
                debugUnit->writeSpr(SPR_NPC, addr);
                debugUnit->writeSpr(SPR_NPC, addr);
        }
        }
}                               // writeNpc ()
}                               // writeNpc ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Read the value of an OpenRISC 1000 General Purpose Register
//! Read the value of an OpenRISC 1000 General Purpose Register
 
 
//! A convenience function. This is just a wrapper for reading a SPR, since
//! A convenience function. This is just a wrapper for reading a SPR, since
//! the GPR's are mapped into SPR space
//! the GPR's are mapped into SPR space
 
 
//! @param[in]  regNum  The GPR to read
//! @param[in]  regNum  The GPR to read
 
 
//! @return  The value of the GPR
//! @return  The value of the GPR
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
uint32_t GdbServerSC::readGpr(int regNum)
uint32_t GdbServerSC::readGpr(int regNum)
{
{
        return debugUnit->readSpr(SPR_GPR0 + regNum);
        return debugUnit->readSpr(SPR_GPR0 + regNum);
 
 
}                               // readGpr ()
}                               // readGpr ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Write the value of an OpenRISC 1000 General Purpose Register
//! Write the value of an OpenRISC 1000 General Purpose Register
 
 
//! A convenience function. This is just a wrapper for writing a SPR, since
//! A convenience function. This is just a wrapper for writing a SPR, since
//! the GPR's are mapped into SPR space
//! the GPR's are mapped into SPR space
 
 
//! @param[in]  regNum  The GPR to read
//! @param[in]  regNum  The GPR to read
 
 
//! @return  The value of the GPR
//! @return  The value of the GPR
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GdbServerSC::writeGpr(int regNum, uint32_t value)
void GdbServerSC::writeGpr(int regNum, uint32_t value)
{
{
        debugUnit->writeSpr(SPR_GPR0 + regNum, value);
        debugUnit->writeSpr(SPR_GPR0 + regNum, value);
 
 
}                               // writeGpr ()
}                               // writeGpr ()
 
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! Check if we received anything via the pipe from the or1200 monitor
//! Check if we received anything via the pipe from the or1200 monitor
 
 
//! We stall the processor, and behave in a manner similar to if an interrupt
//! We stall the processor, and behave in a manner similar to if an interrupt
//! had been received. Perhaps the sigval should be set differently/more
//! had been received. Perhaps the sigval should be set differently/more
//! more appropriately.
//! more appropriately.
//! Read from the pipe should be NON-blocking.
//! Read from the pipe should be NON-blocking.
 
 
//! @return  false if nothing received, else true
//! @return  false if nothing received, else true
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool GdbServerSC::checkMonitorPipe()
bool GdbServerSC::checkMonitorPipe()
{
{
        char readChar;
        char readChar;
        int n = read(monitor_to_gdb_pipe[0][0], &readChar, sizeof(char));
        int n = read(monitor_to_gdb_pipe[0][0], &readChar, sizeof(char));
        if (!(((n < 0) && (errno == EAGAIN)) || (n == 0)) && !targetStopped) {
        if (!(((n < 0) && (errno == EAGAIN)) || (n == 0)) && !targetStopped) {
                debugUnit->stall();
                debugUnit->stall();
                // Send a stop reply response, manually set rsp.sigval to TARGET_SIGNAL_NONE
                // Send a stop reply response, manually set rsp.sigval to TARGET_SIGNAL_NONE
                rsp_sigval = TARGET_SIGNAL_NONE;
                rsp_sigval = TARGET_SIGNAL_NONE;
                rspReportException();
                rspReportException();
                targetStopped = true;   // Processor now not running
                targetStopped = true;   // Processor now not running
                write(monitor_to_gdb_pipe[1][1], &readChar, sizeof(char));
                write(monitor_to_gdb_pipe[1][1], &readChar, sizeof(char));
                return true;
                return true;
        }
        }
 
 
        return false;
        return false;
 
 
}                               // checkMonitorPipe ()
}                               // checkMonitorPipe ()
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.