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

Subversion Repositories openrisc

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

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 66 Rev 425
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
 
// 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>
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<TapAction *> *tapActionQueue) :
                          sc_fifo<TapAction *> *tapActionQueue) :
  sc_module (name),
  sc_module (name),
  flashStart (_flashStart),
  flashStart (_flashStart),
  flashEnd (_flashEnd)
  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) && rsp_sigval == TARGET_SIGNAL_TRAP)
              if (NULL != mpHash->lookup (BP_MEMORY, ppc) && 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
void
GdbServerSC::rspClientRequest ()
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" << endl;
      cerr << "Warning: RSP 'A' packet not supported: ignored" << 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
void
GdbServerSC::rspCheckForException()
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:  rsp_sigval = TARGET_SIGNAL_PWR;  break;
    case SPR_DRR_RSTE:  rsp_sigval = TARGET_SIGNAL_PWR;  break;
    case SPR_DRR_BUSEE: rsp_sigval = TARGET_SIGNAL_BUS;  break;
    case SPR_DRR_BUSEE: rsp_sigval = TARGET_SIGNAL_BUS;  break;
    case SPR_DRR_DPFE:  rsp_sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_DPFE:  rsp_sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_IPFE:  rsp_sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_IPFE:  rsp_sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_TTE:   rsp_sigval = TARGET_SIGNAL_ALRM; break;
    case SPR_DRR_TTE:   rsp_sigval = TARGET_SIGNAL_ALRM; break;
    case SPR_DRR_AE:    rsp_sigval = TARGET_SIGNAL_BUS;  break;
    case SPR_DRR_AE:    rsp_sigval = TARGET_SIGNAL_BUS;  break;
    case SPR_DRR_IIE:   rsp_sigval = TARGET_SIGNAL_ILL;  break;
    case SPR_DRR_IIE:   rsp_sigval = TARGET_SIGNAL_ILL;  break;
    case SPR_DRR_IE:    rsp_sigval = TARGET_SIGNAL_INT;  break;
    case SPR_DRR_IE:    rsp_sigval = TARGET_SIGNAL_INT;  break;
    case SPR_DRR_DME:   rsp_sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_DME:   rsp_sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_IME:   rsp_sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_IME:   rsp_sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_RE:    rsp_sigval = TARGET_SIGNAL_FPE;  break;
    case SPR_DRR_RE:    rsp_sigval = TARGET_SIGNAL_FPE;  break;
    case SPR_DRR_SCE:   rsp_sigval = TARGET_SIGNAL_USR2; break;
    case SPR_DRR_SCE:   rsp_sigval = TARGET_SIGNAL_USR2; break;
    case SPR_DRR_FPE:   rsp_sigval = TARGET_SIGNAL_FPE;  break;
    case SPR_DRR_FPE:   rsp_sigval = TARGET_SIGNAL_FPE;  break;
    case SPR_DRR_TE:    rsp_sigval = TARGET_SIGNAL_TRAP; break;
    case SPR_DRR_TE:    rsp_sigval = TARGET_SIGNAL_TRAP; 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; break;
      rsp_sigval = TARGET_SIGNAL_TRAP; 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
void
GdbServerSC::rspReportException ()
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
void
GdbServerSC::rspContinue (uint32_t   except)
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 << "Warning: Continue with signal not currently supported: "
      cerr << "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
void
GdbServerSC::rspContinue ()
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
void
GdbServerSC::rspContinue (uint32_t  addr,
GdbServerSC::rspContinue (uint32_t  addr,
                          uint32_t  except)
                          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, temp_dmr2 & ~((temp_dmr2&SPR_DMR2_WBS)>>10));
          debugUnit->writeSpr (SPR_DMR2, temp_dmr2 & ~((temp_dmr2&SPR_DMR2_WBS)>>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
void
GdbServerSC::rspInterrupt()
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 << "* Warning: Interrupt character expected but not found on socket" << endl;
      cerr << "* Warning: Interrupt character expected but not found on socket" << 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
void
GdbServerSC::rspReadAllRegs ()
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), &(pkt->data[PPC_REGNUM * 8]));
  Utils::reg2Hex (debugUnit->readSpr (SPR_PPC), &(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
void
GdbServerSC::rspWriteAllRegs ()
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, Utils::hex2Reg (&(pkt->data[PPC_REGNUM * 8])));
  debugUnit->writeSpr (SPR_PPC, Utils::hex2Reg (&(pkt->data[PPC_REGNUM * 8])));
  debugUnit->writeSpr (SPR_SR,  Utils::hex2Reg (&(pkt->data[SR_REGNUM  * 8])));
  debugUnit->writeSpr (SPR_SR,  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
void
GdbServerSC::rspReadMem ()
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
void
GdbServerSC::rspWriteMem ()
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 * 2 << "digits requested, but "
      cerr << "Warning: Write of " << len * 2 << "digits requested, but "
                << datLen << " digits supplied: packet ignored" << endl;
                << datLen << " 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
void
GdbServerSC::rspReadReg ()
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 << "Warning: Failed to recognize RSP read register command: "
      cerr << "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
void
GdbServerSC::rspWriteReg ()
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 << "Warning: Failed to recognize RSP write register command "
      cerr << "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
void
GdbServerSC::rspQuery ()
GdbServerSC::rspQuery ()
{
{
  if (0 == strcmp ("qC", pkt->data))
  if (0 == strcmp ("qAttached", pkt->data))
 
    {
 
      // We are always attaching to an existing process with the bare metal
 
      // embedded system. 
 
      pkt->packStr ("1");
 
      rsp->putPkt (pkt);
 
    }
 
  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 == strncmp ("qGetTLSAddr:", pkt->data, strlen ("qGetTLSAddr:")))
  else if (0 == 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")))
 
    {
 
      // We don't support tracing, return empty packet
 
      pkt->packStr ("");
 
      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
void
GdbServerSC::rspCommand ()
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 << " not recognized: ignored"
          cerr << "Warning: qRcmd " << cmd << " not recognized: ignored"
                    << endl;
                    << 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
void
GdbServerSC::rspSet ()
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
void
GdbServerSC::rspRestart ()
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
void
GdbServerSC::rspStep (uint32_t   except)
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
void
GdbServerSC::rspStep ()
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
void
GdbServerSC::rspStep (uint32_t  addr,
GdbServerSC::rspStep (uint32_t  addr,
                      uint32_t  except)
                      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, temp_dmr2 & ~((temp_dmr2&SPR_DMR2_WBS)>>10));
          debugUnit->writeSpr (SPR_DMR2, temp_dmr2 & ~((temp_dmr2&SPR_DMR2_WBS)>>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
void
GdbServerSC::rspVpkt ()
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 == strncmp ("vFlashErase:", pkt->data, strlen ("vFlashErase:")))
  else if (0 == 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" << endl;
      cerr << "Warning: RSP vFlashErase not supported: ignored" << endl;
      pkt->packStr ("E01");
      pkt->packStr ("E01");
      rsp->putPkt (pkt);
      rsp->putPkt (pkt);
      return;
      return;
    }
    }
  else if (0 == strncmp ("vFlashWrite:", pkt->data, strlen ("vFlashWrite:")))
  else if (0 == 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" << endl;
      cerr << "Warning: RSP vFlashWrite not supported: ignored" << 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" << endl;;
      cerr << "Warning: RSP vFlashDone not supported: ignored" << 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
void
GdbServerSC::rspWriteMemBin ()
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 << "Warning: Failed to recognize RSP write memory command: %s"
      cerr << "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 << " will be written"
           << newLen << " bytes supplied. " << minLen << " will be written"
           << endl;
           << 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
void
GdbServerSC::rspRemoveMatchpoint ()
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->readSpr (SPR_DMR2) & ~((1<<off)<<SPR_DMR2_WGB_SHIFT));
      debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2) & ~((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 ((debugUnit->readSpr (SPR_DCR0+off) == (0x63)) &&
            if ((debugUnit->readSpr (SPR_DCR0+off) == (0x63)) &&
                (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->readSpr (SPR_DMR2) & ~((1<<off)<<SPR_DMR2_WGB_SHIFT));
        debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2) & ~((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 ((debugUnit->readSpr (SPR_DCR0+off) == (0x43)) &&
            if ((debugUnit->readSpr (SPR_DCR0+off) == (0x43)) &&
                (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->readSpr (SPR_DMR2) & ~((1<<off)<<SPR_DMR2_WGB_SHIFT));
        debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2) & ~((1<<off)<<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) == (0xc3)) &&
            if ((debugUnit->readSpr (SPR_DCR0+off) == (0xc3)) &&
                (debugUnit->readSpr (SPR_DVR0+off) == addr))
                (debugUnit->readSpr (SPR_DVR0+off) == 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->readSpr (SPR_DMR2) & ~((1<<off)<<SPR_DMR2_WGB_SHIFT));
        debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2) & ~((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;
    }
    }
}       // 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
void
GdbServerSC::rspInsertMatchpoint ()
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 (!(debugUnit->readSpr (SPR_DCR0+off) & SPR_DCR_CT_MASK))
          if (!(debugUnit->readSpr (SPR_DCR0+off) & 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->readSpr (SPR_DMR2)|((1<<off)<<SPR_DMR2_WGB_SHIFT));
        debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2)|((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 (!(debugUnit->readSpr (SPR_DCR0+off) & SPR_DCR_CT_MASK))
          if (!(debugUnit->readSpr (SPR_DCR0+off) & 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->readSpr (SPR_DMR2)|((1<<off)<<SPR_DMR2_WGB_SHIFT));
        debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2)|((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 (!(debugUnit->readSpr (SPR_DCR0+off) & SPR_DCR_CT_MASK))
          if (!(debugUnit->readSpr (SPR_DCR0+off) & 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->readSpr (SPR_DMR2)|((1<<off)<<SPR_DMR2_WGB_SHIFT));
        debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2)|((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 (!(debugUnit->readSpr (SPR_DCR0+off) & SPR_DCR_CT_MASK))
          if (!(debugUnit->readSpr (SPR_DCR0+off) & 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->readSpr (SPR_DMR2)|((1<<off)<<SPR_DMR2_WGB_SHIFT));
        debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2)|((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
uint32_t
GdbServerSC::readNpc ()
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
void
GdbServerSC::writeNpc (uint32_t  addr)
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
uint32_t
GdbServerSC::readGpr (int  regNum)
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
void
GdbServerSC::writeGpr (int       regNum,
GdbServerSC::writeGpr (int       regNum,
                       uint32_t  value)
                       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
bool
GdbServerSC::checkMonitorPipe ()
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.