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

Subversion Repositories openrisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/orpsocv2/bench/sysc
    from Rev 57 to Rev 63
    Reverse comparison

Rev 57 → Rev 63

/include/RspPacket.h
0,0 → 1,76
// ----------------------------------------------------------------------------
 
// RSP packet: definition
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: RspPacket.h 326 2009-03-07 16:47:31Z jeremy $
 
#ifndef RSP_PACKET__H
#define RSP_PACKET__H
 
#include <iostream>
 
 
//-----------------------------------------------------------------------------
//! Class for RSP packets
 
//! Can't be null terminated, since it may include zero bytes
//-----------------------------------------------------------------------------
class RspPacket
{
public:
 
//! The data buffer. Allow direct access to avoid unnecessary copying.
char *data;
 
// Constructor and destructor
RspPacket (int _bufSize);
~RspPacket ();
 
// Pack a constant string into a packet
void packStr (const char *str); // For fixed packets
// Accessors
int getBufSize ();
int getLen ();
void setLen (int _len);
 
 
private:
 
//! The data buffer size
int bufSize;
 
//! Number of chars in the data buffer (<= bufSize)
int len;
 
};
 
 
//! Stream output
std::ostream &operator<< (std::ostream &s,
RspPacket &p);
 
 
#endif // RSP_PACKET_SC__H
/include/Utils.h
0,0 → 1,66
// ----------------------------------------------------------------------------
 
// GDB Server Utilties: definition
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: Utils.h 324 2009-03-07 09:42:52Z jeremy $
 
#ifndef UTILS_H
#define UTILS_H
 
#include <stdint.h>
 
 
//-----------------------------------------------------------------------------
//! A class offering a number of convenience utilities for the GDB Server.
 
//! All static functions. This class is not intended to be instantiated.
//-----------------------------------------------------------------------------
class Utils
{
public:
 
static uint8_t char2Hex (int c);
static const char hex2Char (uint8_t d);
static void reg2Hex (uint32_t val,
char *buf);
static uint32_t hex2Reg (char *buf);
static void ascii2Hex (char *dest,
char *src);
static void hex2Ascii (char *dest,
char *src);
static int rspUnescape (char *buf,
int len);
static uint32_t htotl (uint32_t hostVal);
static uint32_t ttohl (uint32_t targetVal);
 
 
private:
 
// Private constructor cannot be instantiated
Utils () {};
 
}; // class Utils
 
#endif // UTILS_H
/include/UartSC.h
26,6 → 26,7
#define UART_SC__H
 
#include "systemc.h"
#include <stdint.h>
 
//! Handle UART I/O
 
/include/MemCache.h
0,0 → 1,78
// ----------------------------------------------------------------------------
 
// Debug Unit memory cache: definition
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// 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.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: MemCache.h 326 2009-03-07 16:47:31Z jeremy $
 
#ifndef MEM_CACHE__H
#define MEM_CACHE__H
 
#include <stdint.h>
 
 
//! Module for cacheing memory accesses by the debug unit
 
//! Memory reads and writes through the Debug Unit via JTAG are time
//! consuming - of the order of 1000 CPU clock cycles. However when the
//! processor is stalled the values cannot change, other than through the
//! debug unit, so it makes sense to cache values.
 
//! Cacheing the entire memory is too much (it does need to be cleared when
//! the processor is unstalled. This class provides a cacheing function using
//! a closed hash table.
 
//! In the event of a clash on write, the old value is replaced by the new
//! value.
 
class MemCache
{
public:
 
// Constructor and destructor
MemCache (int _tableSize = 1009);
~MemCache ();
 
// Functions
void clear ();
void write (uint32_t addr,
uint32_t value);
bool read (uint32_t addr,
uint32_t &value);
 
private:
 
//! The size of the hash table. A prime number is a good choice.
int tableSize;
 
// The hash table, keyed by address. Done as three parallel vectors,
// allowing unambiguous clearing by use of memset for efficiency.
bool *tabIsValid;
uint32_t *tabKeyAddr;
uint32_t *tabValue;
 
 
}; // MemCache ()
 
#endif // MEM_CACHE__H
/include/GdbServerSC.h
0,0 → 1,233
// ----------------------------------------------------------------------------
 
// SystemC GDB RSP server: definition
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// 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.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
#ifndef GDB_SERVER_SC__H
#define GDB_SERVER_SC__H
 
#include <stdint.h>
 
#include "systemc"
 
#include "jtagsc.h"
 
#include "OrpsocAccess.h"
#include "RspConnection.h"
#include "MpHash.h"
#include "RspPacket.h"
#include "DebugUnitSC.h"
 
 
//! Module implementing a GDB RSP server.
 
//! A thread listens for RSP requests, which are converted to requests to read
//! and write registers, memory or control the CPU in the debug unit
 
class GdbServerSC
: public sc_core::sc_module
{
public:
 
// Constructor and destructor
GdbServerSC (sc_core::sc_module_name name,
uint32_t _flashStart,
uint32_t _flashEnd,
int rspPort,
sc_core::sc_fifo<TapAction *> *tapActionQueue);
~GdbServerSC ();
 
private:
 
//! Definition of GDB target signals.
 
//! Data taken from the GDB 6.8 source. Only those we use defined here.
enum TargetSignal {
TARGET_SIGNAL_NONE = 0,
TARGET_SIGNAL_INT = 2,
TARGET_SIGNAL_ILL = 4,
TARGET_SIGNAL_TRAP = 5,
TARGET_SIGNAL_FPE = 8,
TARGET_SIGNAL_BUS = 10,
TARGET_SIGNAL_SEGV = 11,
TARGET_SIGNAL_ALRM = 14,
TARGET_SIGNAL_USR2 = 31,
TARGET_SIGNAL_PWR = 32
};
 
// Register numbering. Matches GDB client
static const int MAX_SPRS = 0x10000; //!< Max number of OR1K SPRs
static const int max_gprs = 32; //!< Max number of OR1K GPRs
 
static const int PPC_REGNUM = max_gprs + 0; //!< Previous PC
static const int NPC_REGNUM = max_gprs + 1; //!< Next PC
static const int SR_REGNUM = max_gprs + 2; //!< Supervision Register
 
static const int NUM_REGS = max_gprs + 3; //!< Total GDB registers
 
//! Maximum size of a GDB RSP packet
//static const int RSP_PKT_MAX = NUM_REGS * 8 + 1;
static const int RSP_PKT_MAX = 1024*16;
 
// OpenRISC exception addresses. Only the ones we need to know about
static const uint32_t EXCEPT_NONE = 0x000; //!< No exception
static const uint32_t EXCEPT_RESET = 0x100; //!< Reset
 
// SPR numbers
static const uint16_t SPR_NPC = 0x0010; //!< Next program counter
static const uint16_t SPR_SR = 0x0011; //!< Supervision register
static const uint16_t SPR_PPC = 0x0012; //!< Previous program counter
static const uint16_t SPR_GPR0 = 0x0400; //!< GPR 0
 
static const uint16_t SPR_DVR0 = 0x3000; //!< Debug value register 0
static const uint16_t SPR_DVR1 = 0x3001; //!< Debug value register 1
static const uint16_t SPR_DVR2 = 0x3002; //!< Debug value register 2
static const uint16_t SPR_DVR3 = 0x3003; //!< Debug value register 3
static const uint16_t SPR_DVR4 = 0x3004; //!< Debug value register 4
static const uint16_t SPR_DVR5 = 0x3005; //!< Debug value register 5
static const uint16_t SPR_DVR6 = 0x3006; //!< Debug value register 6
static const uint16_t SPR_DVR7 = 0x3007; //!< Debug value register 7
 
static const uint16_t SPR_DCR0 = 0x3008; //!< Debug control register 0
static const uint16_t SPR_DCR1 = 0x3009; //!< Debug control register 1
static const uint16_t SPR_DCR2 = 0x300a; //!< Debug control register 2
static const uint16_t SPR_DCR3 = 0x300b; //!< Debug control register 3
static const uint16_t SPR_DCR4 = 0x300c; //!< Debug control register 4
static const uint16_t SPR_DCR5 = 0x300d; //!< Debug control register 5
static const uint16_t SPR_DCR6 = 0x300e; //!< Debug control register 6
static const uint16_t SPR_DCR7 = 0x300f; //!< Debug control register 7
 
static const uint16_t SPR_DMR1 = 0x3010; //!< Debug mode register 1
static const uint16_t SPR_DMR2 = 0x3011; //!< Debug mode register 2
static const uint16_t SPR_DSR = 0x3014; //!< Debug stop register
static const uint16_t SPR_DRR = 0x3015; //!< Debug reason register
 
// SPR masks and offsets
static const uint32_t SPR_DMR1_ST = 0x00400000; //!< Single-step trace
static const uint32_t SPR_DMR2_WGB = 0x003ff000; //!< W/pt generating B/pt
static const uint32_t SPR_DMR2_WBS = 0xffc00000; //!< W/pt B/pt status
static const uint32_t SPR_DSR_TE = 0x00002000; //!< Trap
static const uint32_t SPR_DCR_DP_MASK = 0x00000001; //!< Debug Pair Present
static const uint32_t SPR_DCR_CC_MASK = 0x0000000e; //!< Compare Condition
static const uint32_t SPR_DCR_SC_MASK = 0x00000010; //!< Signed Comparison
static const uint32_t SPR_DCR_CT_MASK = 0x000000e0; //!< Compare To
static const uint32_t SPR_DMR2_WGB_SHIFT = 12; //!< W/pt Generate B/pt
 
 
// DRR (Debug Reason Register) Bits
static const uint32_t SPR_DRR_RSTE = 0x00000001; //!< Reset
static const uint32_t SPR_DRR_BUSEE = 0x00000002; //!< Bus error
static const uint32_t SPR_DRR_DPFE = 0x00000004; //!< Data page fault
static const uint32_t SPR_DRR_IPFE = 0x00000008; //!< Insn page fault
static const uint32_t SPR_DRR_TTE = 0x00000010; //!< Tick timer
static const uint32_t SPR_DRR_AE = 0x00000020; //!< Alignment
static const uint32_t SPR_DRR_IIE = 0x00000040; //!< Illegal instruction
static const uint32_t SPR_DRR_IE = 0x00000080; //!< Interrupt
static const uint32_t SPR_DRR_DME = 0x00000100; //!< DTLB miss
static const uint32_t SPR_DRR_IME = 0x00000200; //!< ITLB miss
static const uint32_t SPR_DRR_RE = 0x00000400; //!< Range fault
static const uint32_t SPR_DRR_SCE = 0x00000800; //!< System call
static const uint32_t SPR_DRR_FPE = 0x00001000; //!< Floating point
static const uint32_t SPR_DRR_TE = 0x00002000; //!< Trap
 
//! RSP Signal valu
uint32_t rsp_sigval;
 
//! Trap instruction for OR32
static const uint32_t OR1K_TRAP_INSTR = 0x21000001;
 
//! Thread ID used by Or1ksim
static const int OR1KSIM_TID = 1;
 
// The bounds of flash memory
uint32_t flashStart; //<! Start of flash memory
uint32_t flashEnd; //<! End of flash memory
 
//! Our associated Debug Unit
DebugUnitSC *debugUnit;
 
//! Our associated RSP interface (which we create)
RspConnection *rsp;
 
//! The packet pointer. There is only ever one packet in use at one time, so
//! there is no need to repeatedly allocate and delete it.
RspPacket *pkt;
 
//! Hash table for matchpoints
MpHash *mpHash;
 
//! Is the target stopped
bool targetStopped;
 
// SystemC thread to listen for and service RSP requests
void rspServer ();
 
// Main RSP request handler
void rspClientRequest ();
 
// Handle the various RSP requests
void rspCheckForException();
void rspReportException ();
void rspContinue ();
void rspContinue (uint32_t except);
void rspContinue (uint32_t addr,
uint32_t except);
void rspInterrupt ();
void rspReadAllRegs ();
void rspWriteAllRegs ();
void rspReadMem ();
void rspWriteMem ();
void rspReadReg ();
void rspWriteReg ();
void rspQuery ();
void rspCommand ();
void rspSet ();
void rspRestart ();
void rspStep ();
void rspStep (uint32_t except);
void rspStep (uint32_t addr,
uint32_t except);
void rspVpkt ();
void rspWriteMemBin ();
void rspRemoveMatchpoint ();
void rspInsertMatchpoint ();
 
// Convenience wrappers for getting particular registers, which are really
// SPRs.
uint32_t readNpc ();
void writeNpc (uint32_t addr);
 
uint32_t readGpr (int regNum);
void writeGpr (int regNum,
uint32_t value);
 
// Check if we got a message from the or1200 monitor module telling us
// to stall
bool checkMonitorPipe ();
 
}; // GdbServerSC ()
 
#endif // GDB_SERVER_SC__H
/include/TapStateMachine.h
0,0 → 1,146
// ----------------------------------------------------------------------------
 
// The TAP state machine: definition
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
#ifndef TAP_STATE_MACHINE__H
#define TAP_STATE_MACHINE__H
 
//! Enumeration of all the states in the TAP state machine.
 
//! Last entry is not a state, but a marker of the number of states. Useful
//! for state transition matrices.
enum TapState {
TAP_TEST_LOGIC_RESET = 0,
TAP_RUN_TEST_IDLE = 1,
TAP_SELECT_DR_SCAN = 2,
TAP_CAPTURE_DR = 3,
TAP_SHIFT_DR = 4,
TAP_EXIT1_DR = 5,
TAP_PAUSE_DR = 6,
TAP_EXIT2_DR = 7,
TAP_UPDATE_DR = 8,
TAP_SELECT_IR_SCAN = 9,
TAP_CAPTURE_IR = 10,
TAP_SHIFT_IR = 11,
TAP_EXIT1_IR = 12,
TAP_PAUSE_IR = 13,
TAP_EXIT2_IR = 14,
TAP_UPDATE_IR = 15,
TAP_SIZE = 16
 
}; // enum TapState
 
 
//! Textual representation of all the TAP states.
 
//! Provided for debugging purposes
static const char *tapStateNames[TAP_SIZE] = {
"Test-Logic-Reset",
"Run-Test/Idle",
"Select-DR-Scan",
"Capture-DR",
"Shift-DR",
"Exit1-DR",
"Pause-DR",
"Exit2-DR",
"Update-DR",
"Select-IR-Scan",
"Capture-IR",
"Shift-IR",
"Exit1-IR",
"Pause-IR",
"Exit2-IR",
"Update-IR"
 
}; // tapStateNames
 
 
//! TAP state machine
 
//! Tracks the state of the TAP. This should mirror the state of the TAP in
//! the connected HW.
 
//! The state machine is created in the reset condition, but in truth we
//! cannot know what the state is. It is essential the TAP is reset before
//! first being used.
 
//! We cannot know for certain when the TAP state machine has been reset. 5
//! consecutive TMS=1 transitions will take you there, but a reset of the
//! target could undo this. It is the responsibility of the user of the TAP
//! state machine.
 
//! For convenience of users, this class provides a flag (resetDone::),
//! with accessors by which reset state can be recorded.
 
 
class TapStateMachine
{
public:
 
friend class JtagSC;
friend class TapAction;
friend class TapActionDRScan;
friend class TapActionIRScan;
friend class TapActionReset;
 
 
protected:
 
//! The number of cycles of TMS=1 required to force reset
static const int TAP_RESET_CYCLES = 5;
 
// Constructor
TapStateMachine();
 
// Accessor for TAP state
TapState getState ();
 
// Accessors for TAP reset state
bool getResetDone ();
void setResetDone (bool _resetState);
 
// Drive the TAP state machine
void nextState (bool tms);
 
// Determine if we are in a particular target state
bool targetState (TapState target,
bool &tms);
 
private:
 
//! The current TAP state
TapState state;
 
//! True if the TAP state machine has been through a reset.
 
//! The state can be sure to match that of the target. Responsibility of
//! user classes to set this.
bool resetDone;
 
}; // class TapStateMachine
 
 
#endif // TAP_STATE_MACHINE__H
/include/OrpsocMain.h
59,4 → 59,27
//! Currently is 32MB (8M words)
#define ORPSOC_SRAM_SIZE (8388608*4)
 
//! Ratio of JTAG clock period to CPU clock period
#define CLOCK_RATIO 10
 
//! JTAG clock half period in timescale units
#define JTAG_CLK_HALFPERIOD (CLOCK_RATIO * BENCH_CLK_HALFPERIOD)
 
//! Start of 2MB Flash memory
#define FLASH_START 0xf0000000
 
//! End of 2MB Flash memory
#define FLASH_END 0xf01fffff
 
//! Default port for RSP to listen on
#define DEFAULT_RSP_PORT 51000
 
//! FIFO size for talking to the RSP connection
#define RSP_FIFO_SIZE 8
 
//! Maximum size of a RSP packet is used to return the value of all the
//! registers, each of which takes 8 chars. There are a total of 32 GPRs plus
//! PPC, SR and NPC. Plus one byte for end of string marker.
#define RSP_MAX_PKT_SIZE ((32 + 3) * 8 + 1)
 
#endif // ORPSOC_MAIN__H
/include/jtagsc.h
0,0 → 1,37
// ----------------------------------------------------------------------------
 
// Unified Header file for the Embecosm cycle accurate SystemC JTAG library
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
 
#include "JtagSC.h"
#include "TapActionDRScan.h"
#include "TapAction.h"
#include "TapActionIRScan.h"
#include "TapActionReset.h"
#include "TapStateMachine.h"
/include/JtagSC.h
0,0 → 1,111
// ----------------------------------------------------------------------------
 
// Main module providing the JTAG interface: definition
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
#ifndef JTAG_SC__H
#define JTAG_SC__H
 
#include "systemc"
#include "TapAction.h"
 
 
//! Default size of the FIFO queuing TAP actions
#define DEFAULT_TAP_FIFO_SIZE 256
 
//! The main JTAG interface module
 
//! This provides a pin interface on one side (to drive JTAG ports on a chip)
//! and a FIFO on the other, allowing the user to queue JTAG actions.
 
//! The pin interface is:
//! - sysReset (input) The system reset. When this is asserted, the interface
//! will do nothing except drive TRST low.
//! - tck (input) The JTAG clock (supplied externally)
//! - tdi (output) Drives the TDI pin
//! - tdo (input) Receives the TDO pin
//! - tms (output) Drives the TMS pin
//! - trst (output) Drives the TRST pin
 
//! @note The JTAG pins are reversed, because this module is @b driving the
//! pins.
 
//! The FIFO allows the user to queue actions, which are of abstract type
//! TapAction::. This is subclassed to provide specific actions for reset
//! (TapActionReset::), DR-scan (TapActionDRScan::) and IR-scan
//! (TapActionIRScan::).
 
//! The size of the FIFO can optionally be specified in the constructor.
 
//! The class provides a method, sensitive to the clock, which reads actions
//! from the FIFO and processes them, issuing the requisite sequence of
//! changes of the JTAG pins until the action is complete. It then notifies
//! the action owner of completion, through an sc_event, which is part of the
//! ::TapAction class.
//!
class JtagSC
: public sc_core::sc_module
{
public:
 
// The ports. Note that the naming of the low level JTAG ports is reversed,
// because we are driving the inputs! */
sc_core::sc_in<bool> sysReset; //!< The system reset (active high)
 
sc_core::sc_in<bool> tck; //!< External JTAG TCK
sc_core::sc_out<bool> tdi; //!< JTAG TDI pin
sc_core::sc_in<bool> tdo; //!< JTAG TDO pin
sc_core::sc_out<bool> tms; //!< JTAG TMS pin
sc_core::sc_out<bool> trst; //!< JTAG TRST pin
 
//! JTAG action queue
sc_core::sc_fifo<TapAction *> *tapActionQueue;
 
// Constructor and destructor
JtagSC (sc_core::sc_module_name name,
int fifo_size = DEFAULT_TAP_FIFO_SIZE);
~JtagSC ();
 
 
protected:
 
// Method to process the actions
void processActions();
 
 
private:
 
//! The TAP state machine
TapStateMachine *stateMachine;
 
//! The next TAP action
TapAction *currentTapAction;
 
}; // JtagSC ()
 
#endif // JTAG_SC__H
/include/DebugUnitSC.h
0,0 → 1,250
// ----------------------------------------------------------------------------
 
// SystemC OpenRISC 1000 Debug Unit: definition
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// 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.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: DebugUnitSC.h 331 2009-03-12 17:01:48Z jeremy $
 
#ifndef DEBUG_UNIT_SC__H
#define DEBUG_UNIT_SC__H
 
 
// Define if no cache is wanted
#define NOCACHE
 
#include <stdint.h>
 
#include "systemc"
 
#include "jtagsc.h"
#include "OrpsocAccess.h"
#include "SprCache.h"
#include "MemCache.h"
 
 
//-----------------------------------------------------------------------------
//! Module modeling the OpenRISC 1000 Debug Unit
 
//! Provides a high level interface to the GDB Server module with functions to
//! access SPRs, Wishbone memory and CPU control.
 
//! Provides a low level interface to the Embecosm SystemC JTAG interface,
//! queueing requests to read and write JTAG registers.
//-----------------------------------------------------------------------------
class DebugUnitSC
: public sc_core::sc_module
{
public:
 
// Constructor and destructor
DebugUnitSC (sc_core::sc_module_name name,
sc_core::sc_fifo<TapAction *> *_tapActionQueue);
~DebugUnitSC ();
 
// Reset function for the debug unit
void resetDebugUnit ();
 
// Functions to control and report on the CPU
void reset ();
void stall ();
void unstall ();
bool isStalled ();
 
// Functions to access SPRs
uint32_t readSpr (uint16_t sprNum);
void writeSpr (uint16_t sprNum,
uint32_t value);
void andSpr (uint16_t sprNum,
uint32_t value);
void orSpr (uint16_t sprNum,
uint32_t value);
 
// Functions to access memory
uint32_t readMem32 (uint32_t addr);
bool writeMem32 (uint32_t addr,
uint32_t value);
uint8_t readMem8 (uint32_t addr);
bool writeMem8 (uint32_t addr,
uint8_t value);
 
private:
 
// JTAG instructions
static const uint32_t CHAIN_SELECT_IR = 0x3; //!< Chain Select instruction
static const uint32_t DEBUG_IR = 0x8; //!< Debug instruction
 
//! JTAG instruction register length. There is no CRC for this register.
static const int JTAG_IR_LEN = 4; //!< JTAG instr reg length
 
// DEBUG UNIT CHAIN data register fields
static const int DUSEL_DR_LEN = 73; //!< total DUSEL DR size
static const int DUSEL_SEL_OFF = 0; //!< start of select field
static const int DUSEL_SEL_LEN = 1; //!< length of select field
static const int DUSEL_OPCODE_OFF = DUSEL_SEL_OFF + DUSEL_SEL_LEN; //!< start of opcode field
static const int DUSEL_OPCODE_LEN = 4; //!< length of opcode field
static const int DUSEL_CRC_OFF = DUSEL_OPCODE_OFF + DUSEL_OPCODE_LEN; //!< start of CRC field
static const int DUSEL_CRC_LEN = 32; //!< length of CRC field
static const int DUSEL_RESP_STATUS_OFF = DUSEL_CRC_OFF + DUSEL_CRC_LEN;
static const int DUSEL_RESP_STATUS_LEN = 4;
static const int DUSEL_RESP_CRC_OFF = DUSEL_RESP_STATUS_OFF + DUSEL_RESP_STATUS_LEN;
static const int DUSEL_RESP_CRC_LEN = 32;
 
static const uint32_t DBG_CRC32_POLY = 0x04c11db7;
// OpenRISC 1000 scan chains (values in DUSEL data register field)
static const int OR1K_SC_UNDEF = -1; //!< Undefined OR1K scan chain
static const int OR1K_SC_WISHBONE = 0; //!< for memory access
static const int OR1K_SC_CPU0 = 1; //!< for access to CPU0
static const int OR1K_SC_CPU1 = 2; //!< for access to CPU1
 
 
 
// JTAG RISC_DEBUG (for accessing SPR) data register fields
static const int RISC_DEBUG_DR_LEN = 74; //!< Total RISC_DEBUG DR size
static const int RISC_DEBUG_ADDR_OFF = 0; //!< start of address field
static const int RISC_DEBUG_ADDR_LEN = 32; //!< length of address field
static const int RISC_DEBUG_RW_OFF = 32; //!< start of read/write field
static const int RISC_DEBUG_RW_LEN = 1; //!< length of read/write field
static const int RISC_DEBUG_DATA_OFF = 33; //!< start of data field
static const int RISC_DEBUG_DATA_LEN = 32; //!< length of data field
static const int RISC_DEBUG_CRC_OFF = 65; //!< start of CRC field
static const int RISC_DEBUG_CRC_LEN = 8; //!< length of CRC field
static const int RISC_DEBUG_SPARE_OFF = 73; //!< start of spare bits
static const int RISC_DEBUG_SPARE_LEN = 1; //!< length of spare bit field
 
// JTAG REGISTER (for controlling the CPU) data register fields
static const int REGISTER_DR_LEN = 47; //!< Total REGISTER DR size
static const int REGISTER_ADDR_OFF = 0; //!< start of address field
static const int REGISTER_ADDR_LEN = 5; //!< length of address field
static const int REGISTER_RW_OFF = 5; //!< start of read/write field
static const int REGISTER_RW_LEN = 1; //!< length of read/write field
static const int REGISTER_DATA_OFF = 6; //!< start of data field
static const int REGISTER_DATA_LEN = 32; //!< length of data field
static const int REGISTER_CRC_OFF = 38; //!< start of CRC field
static const int REGISTER_CRC_LEN = 8; //!< length of CRC field
static const int REGISTER_SPARE_OFF = 46; //!< start of spare bits
static const int REGISTER_SPARE_LEN = 1; //!< length of spare bit field
 
// Register addresses for the REGISTER scan chain
static const uint8_t OR1K_RSC_RISCOP = 0x04; //!< Used to reset/stall CPU
 
// Bits for the RISCOP register
static const uint32_t RISCOP_RESET = 0x00000001; //!< Reset the CPU
static const uint32_t RISCOP_STALL = 0x00000002; //!< Stall the CPU
 
// JTAG WISHBONE (for accessing SPR) data register fields
static const int WISHBONE_DR_LEN = 74; //!< Total WISHBONE DR size
static const int WISHBONE_ADDR_OFF = 0; //!< start of address field
static const int WISHBONE_ADDR_LEN = 32; //!< length of address field
static const int WISHBONE_RW_OFF = 32; //!< start of read/write field
static const int WISHBONE_RW_LEN = 1; //!< length of read/write field
static const int WISHBONE_DATA_OFF = 33; //!< start of data field
static const int WISHBONE_DATA_LEN = 32; //!< length of data field
static const int WISHBONE_CRC_OFF = 65; //!< start of CRC field
static const int WISHBONE_CRC_LEN = 8; //!< length of CRC field
static const int WISHBONE_SPARE_OFF = 73; //!< start of spare bits
static const int WISHBONE_SPARE_LEN = 1; //!< length of spare bit field
 
//! The NPC is special, so we need to know about it
static const int SPR_NPC = 0x10;
 
//! The JTAG fifo we queue on
sc_core::sc_fifo<TapAction *> *tapActionQueue;
 
//! The processor stall state. When stalled we can use cacheing on
//! reads/writes of memory and SPRs.
enum {
UNKNOWN,
STALLED,
} stallState;
 
//! The currently selected scan chain
int currentScanChain;
 
#ifdef NOCACHE
//! Even if no cached, we need to cache the NPC
uint32_t npcCachedValue;
 
//! Cached NPC is valid
bool npcCacheIsValid;
 
#else
//! The SPR cache
SprCache *sprCache;
 
//! The memory cache
MemCache *memCache;
#endif
 
// Functions to control the CPU
uint32_t readRiscop ();
void writeRiscop (uint32_t value);
 
// Or1k JTAG actions
void selectDebugModule (int chain);
uint32_t readJtagReg (uint32_t addr);
uint32_t readJtagReg1 (uint32_t addr,
int bitSizeNoCrc);
uint32_t readJtagReg1 (uint64_t *dRegArray,
uint32_t addr,
int bitSizeNoCrc);
void writeJtagReg (uint32_t addr,
uint32_t data);
 
// Utilities to pack and unpack bits to/from data registers.
void clearBits (uint64_t regArray[],
int regBits);
 
void packBits (uint64_t regArray[],
int fieldOffset,
int fieldBits,
uint64_t fieldVal);
 
uint64_t unpackBits (uint64_t regArray[],
int fieldOffset,
int fieldBits);
 
// Utility to compute CRC-8 the OpenRISC way.
uint8_t crc8 (uint64_t dataArray[],
int size);
// Utility to compute CRC-32 for the debug unit
uint32_t crc32 (uint64_t dataArray[],
int size,
int offset);
 
// Functions to bitreverse values
uint32_t bit_reverse_swar_2(uint32_t x);
uint32_t bit_reverse_swar_4(uint32_t x);
uint32_t bit_reverse_swar_8(uint32_t x);
uint32_t bit_reverse_swar_16(uint32_t x);
uint32_t bit_reverse_swar_32(uint32_t x);
#define BITREV(x,y) bit_reverse_data(x,y)
uint32_t bit_reverse_data(uint32_t x, int length);
 
 
 
}; // DebugUnitSC ()
 
#endif // DEBUG_UNIT_SC__H
/include/TapActionDRScan.h
0,0 → 1,139
// ----------------------------------------------------------------------------
 
// TAP DR-Scan action: definition
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
 
#ifndef TAP_ACTION_DR_SCAN__H
#define TAP_ACTION_DR_SCAN__H
 
#include <stdint.h>
 
#include "TapAction.h"
#include "TapStateMachine.h"
 
 
//! Class to represent a TAP DR-Scan action.
 
//! JTAG data registers can be huge and are represented generically as arrays
//! of uint64_t. However for efficiency versions of methods are provided based
//! on a single uint64_t.
 
//! The SystemC classes for large unsigned ints are fabulously inefficient in
//! the reference implementation, so are not used here.
 
class TapActionDRScan
: public TapAction
{
public:
 
// Constructors and destructor
TapActionDRScan (sc_core::sc_event *_doneEvent,
uint64_t _dRegInArray[],
int _dRegSize);
TapActionDRScan (sc_core::sc_event *_doneEvent,
uint64_t _dRegIn,
int _dRegSize);
TapActionDRScan (sc_core::sc_event *_doneEvent,
uint64_t _dRegInArray[],
int _dRegSize,
int _goToPauseState,
int _bitsBeforePauseState);
TapActionDRScan (sc_core::sc_event *_doneEvent,
uint64_t _dRegIn,
int _dRegSize,
int _goToPauseState,
int _bitsBeforePauseState);
~TapActionDRScan ();
 
// Get the shifted out value
void getDRegOut (uint64_t dRegArray[]);
uint64_t getDRegOut ();
 
 
protected:
 
// Process the action for IR-Scan
bool process (TapStateMachine *tapStateMachine,
bool &tdi,
bool tdo,
bool &tms);
 
 
private:
 
//! Number of bits in the data register
int dRegBitSize;
 
//! Number of uint64_t words in the data register
int dRegWordSize;
 
//! Mask for top word in multi-word register
uint64_t topMask;
 
//! The value being shifted in
uint64_t *dRegInArray;
 
//! The value being shifted in (small version optimization)
uint64_t dRegIn;
 
//! The value shifted out
uint64_t *dRegOutArray;
 
//! The value being shifted out (small version optimization)
uint64_t dRegOut;
 
//! Should we go to PAUSE state and poll tdo during operation?
int goToPauseState;
 
//! Number of bits to shift before going to PAUSE state and polling tdo
int bitsBeforePause;
 
int pauseStateCount;
 
//! Bits shifted so far
int bitsShifted;
 
//! Where we are in the Shift-DR process
enum {
SHIFT_DR_PREPARING,
SHIFT_DR_SHIFTING,
SHIFT_DR_SHIFTING_BEFORE_PAUSE,
SHIFT_DR_SHIFTING_PAUSE,
SHIFT_DR_EXIT2,
SHIFT_DR_SHIFTING_AFTER_PAUSE,
SHIFT_DR_UPDATING
} dRScanState;
 
// Utilities to shift the bottom bit out and top bit in
bool shiftDRegOut ();
void shiftDRegIn (bool bitIn);
 
}; // TapActionDRScan
 
#endif // TAP_ACTION_DR_SCAN__H
/include/MpHash.h
0,0 → 1,105
// ----------------------------------------------------------------------------
 
// Matchpoint hash table: definition
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: MpHash.h 317 2009-02-22 19:52:12Z jeremy $
 
#ifndef MP_HASH__H
#define MP_HASH__H
 
#include <stdint.h>
 
 
//! Default size of the matchpoint hash table. Largest prime < 2^10
#define DEFAULT_MP_HASH_SIZE 1021
 
 
//! Enumeration of different types of matchpoint.
 
//! These have explicit values matching the second digit of 'z' and 'Z'
//! packets.
enum MpType {
BP_MEMORY = 0,
BP_HARDWARE = 1,
WP_WRITE = 2,
WP_READ = 3,
WP_ACCESS = 4
};
 
 
class MpHash;
 
//! A structure for a matchpoint hash table entry
struct MpEntry
{
public:
 
friend class MpHash; // The only one which can get at next
 
MpType type; //!< Type of matchpoint
uint32_t addr; //!< Address with the matchpoint
uint32_t instr; //!< Substituted instruction
 
 
private:
 
MpEntry *next; //!< Next in this slot
};
 
 
//! A hash table for matchpoints
 
//! We do this as our own open hash table. Our keys are a pair of entities
//! (address and type), so STL map is not trivial to use.
 
class MpHash
{
public:
 
// Constructor and destructor
MpHash (int _size = DEFAULT_MP_HASH_SIZE);
~MpHash ();
 
// Accessor methods
void add (MpType type,
uint32_t addr,
uint32_t instr);
MpEntry *lookup (MpType type,
uint32_t addr);
bool remove (MpType type,
uint32_t addr,
uint32_t *instr = NULL);
 
private:
 
//! The hash table
MpEntry **hashTab;
 
//! Size of the hash table
int size;
 
};
 
#endif // MP_HASH__H
/include/Or1200MonitorSC.h
61,6 → 61,7
 
// Methods to setup and output state of processor to a file
void displayState();
void displayStateBinary();
 
// Methods to generate the call and return list during execution
void callLog();
77,14 → 78,19
// Method to dump simulation's RAM contents at finish
void memdump();
 
// Method used for monitoring and logging transactions on the system bus
void busMonitor();
 
 
// The ports
sc_in<bool> clk;
 
private:
 
#define DEFAULT_EXEC_LOG_FILE "or1200_exec.log"
#define DEFAULT_PROF_FILE "sim.profile"
#define DEFAULT_MEMDUMP_FILE "vorpsoc_ram.dump"
#define DEFAULT_BUS_LOG_FILE "bus_trans.log"
 
// Special NOP instructions
static const uint32_t NOP_NOP = 0x15000000; //!< Normal nop instruction
92,19 → 98,35
static const uint32_t NOP_REPORT = 0x15000002; //!< Simple report
static const uint32_t NOP_PRINTF = 0x15000003; //!< Simprintf instruction
static const uint32_t NOP_PUTC = 0x15000004; //!< Putc instruction
static const uint32_t NOP_CNT_RESET = 0x15000005; //!< Reset statistics counters
static const uint32_t NOP_MEM_STATS_RESET = 0x15000010; //!< Reset memory statistics counters
static const uint32_t NOP_CNT_RESET_DIFFERENCE = 0x15000006; //!< Reset stats counters, print
 
// Variables for processor status output
ofstream statusFile;
ofstream profileFile;
int profiling_enabled;
int logging_enabled;
int exit_perf_summary_enabled;
int insn_count;
long long cycle_count;
bool profiling_enabled;
bool logging_enabled;
bool logfile_name_provided;
bool logging_regs;
bool binary_log_format;
bool exit_perf_summary_enabled;
bool monitor_for_crash;
int lookslikewevecrashed_count, crash_monitor_buffer_head;
#define CRASH_MONITOR_BUFFER_SIZE 32
uint32_t crash_monitor_buffer[CRASH_MONITOR_BUFFER_SIZE][2]; //PC, Insn
bool wait_for_stall_cmd_response;
unsigned long long insn_count, insn_count_rst;
unsigned long long cycle_count, cycle_count_rst;
ofstream memdumpFile;
string memdumpFileName;
int do_memdump, memdump_start_addr, memdump_end_addr;
bool do_memdump;
int memdump_start_addr, memdump_end_addr;
bool bus_trans_log_enabled, bus_trans_log_name_provided, bus_trans_log_start_delay_enable;
sc_time bus_trans_log_start_delay;
enum busLogStates { BUS_LOG_IDLE, BUS_LOG_WAIT_FOR_ACK };
ofstream busTransLog;
 
//! Time measurement variable - for calculating performance of the sim
clock_t start;
 
112,7 → 134,7
OrpsocAccess *accessor;
 
//! The memory loading object
MemoryLoad *memoryload;
MemoryLoad *memoryload;
 
}; // Or1200MonitorSC ()
 
/include/TapAction.h
0,0 → 1,99
// ----------------------------------------------------------------------------
 
// TAP action header: abstract class definition
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
 
#ifndef TAP_ACTION__H
#define TAP_ACTION__H
 
#include "TapStateMachine.h"
 
namespace sc_core
{
class sc_event;
}
 
 
//! Enumeration of all the TAP actions supported.
 
enum TapActionType {
TAP_ACTION_RESET = 0,
TAP_ACTION_SHIFT_DR = 1,
TAP_ACTION_SHIFT_IR = 2
};
 
 
//! Abstract class to represent a TAP action.
 
//! Subclasses implement specific actions: Reset (TapActionReset::), DR-Scan
//! (TapActionDRScan::) and IR-Scan (TapActionIRScan::).
 
//! We keep a SystemC event, which is used to notify the creator of
//! completion. Since we are not a SystemC class, we don't do the notification
//! ourselves.
 
class TapAction
{
public:
 
friend class JtagSC;
 
// Constructor
TapAction (sc_core::sc_event *_doneEvent);
 
 
protected:
 
// Accessor for the SystemC event to notify completion
sc_core::sc_event *getDoneEvent ();
 
// Process the action. Pure virtual, so must be implemented by subclasses.
virtual bool process (TapStateMachine *tapStateMachine,
bool &tdi,
bool tdo,
bool &tms) = 0;
 
// Function to drive the TAP to a consistent state, optionally with a
// warning.
bool checkResetDone (TapStateMachine *tapStateMachine,
bool &tms,
bool warn = false);
 
 
private:
 
//! The associated SystemC event to mark completion
sc_core::sc_event *doneEvent;
 
//! Counter for the reset process
int resetCounter;
 
}; // TapAction ()
 
#endif // TAP_ACTION__H
/include/TapActionIRScan.h
0,0 → 1,95
// ----------------------------------------------------------------------------
 
// TAP IR-Scan action: definition
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
 
#ifndef TAP_ACTION_IR_SCAN__H
#define TAP_ACTION_IR_SCAN__H
 
#include <stdint.h>
 
#include "TapAction.h"
#include "TapStateMachine.h"
 
 
//! Class to represent a TAP IR-Scan action.
 
//! This class assumes that JTAG instruction registers are relatively
//! small. IEEE 1149.1 mandates at least 2 bits, although implementations
//! often have a wider range of instructions. The OpenRISC 1000 debug unit for
//! example uses 5 bits. 32-bits seems more than enough for the largest
//! applications.
 
class TapActionIRScan
: public TapAction
{
public:
 
// Constructor
TapActionIRScan (sc_core::sc_event *_doneEvent,
uint32_t _iRegIn,
int _iRegSize);
 
// Get the shifted out value
uint32_t getIRegOut ();
 
 
protected:
 
// Process the action for IR-Scan
bool process (TapStateMachine *tapStateMachine,
bool &tdi,
bool tdo,
bool &tms);
 
 
private:
 
//! The value being shifted in
uint32_t iRegIn;
 
//! The number of bits to shift
int iRegSize;
 
//! The value shifted out
uint32_t iRegOut;
 
//! The number of bits shifted so far
int bitsShifted;
 
//! Where we are in the IR-scan process
enum {
SHIFT_IR_PREPARING,
SHIFT_IR_SHIFTING,
SHIFT_IR_UPDATING
} iRScanState;
 
}; // TapActionIRScan
 
#endif // TAP_ACTION_IR_SCAN__H
/include/RspConnection.h
0,0 → 1,102
// ----------------------------------------------------------------------------
 
// Remote Serial Protocol connection: definition
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: RspConnection.h 326 2009-03-07 16:47:31Z jeremy $
 
#ifndef RSP_CONNECTION__H
#define RSP_CONNECTION__H
 
#include "RspPacket.h"
 
 
//! The default service to use if port number = 0 and no service specified
#define DEFAULT_RSP_SERVICE "or1ksim-rsp"
 
 
//-----------------------------------------------------------------------------
//! Class implementing the RSP connection listener
 
//! RSP requests received from TCP/IP are queued on the output FIFO for
//! processing by the GDB server. Packets read from the input FIFO from the
//! GDB server are sent back via TCP/IP.
 
//! The packets are received serially, ie. a new packet is not sent until the
//! previous ones have been dealt with. Some packets need no reply, so they
//! will be sent one after the other. But for packets that need a reply (which
//! may be one or several packets), new packets are not sent until the reply
//! from the previous one is received.
 
//! The upshot of this is that we can avoid any risk of deadlock by always
//! giving priority to any outgoing reply packets.
 
//! Two threads are used, one to listen for TCP/IP connections from the
//! client, the other to look for FIFO packets from the GDB server to write
//! back to the client. Both must be non-blocking in the SystemC sense
//! (i.e. allow other SystemC threads to run).
//-----------------------------------------------------------------------------
class RspConnection
{
public:
 
// Constructors and destructor
RspConnection (int _portNum);
RspConnection (const char *_serviceName = DEFAULT_RSP_SERVICE);
~RspConnection ();
 
// Public interface: manage client connections
bool rspConnect ();
void rspClose ();
bool isConnected ();
char rspSocketPeek ();
// Public interface: get packets from the stream and put them out
bool getPkt (RspPacket *pkt);
bool putPkt (RspPacket *pkt);
int getRspChar ();
 
private:
 
// Generic initializer
void rspInit (int _portNum,
const char *_serviceName);
 
// Internal routines to handle individual chars
bool putRspChar (char c);
//int getRspChar ();
 
//! The port number to listen on
int portNum;
 
//! The service name to listen on
const char *serviceName;
 
//! The client file descriptor
int clientFd;
 
}; // RspConnection ()
 
#endif // RSP_CONNECTION__H
/include/TapActionReset.h
0,0 → 1,69
// ----------------------------------------------------------------------------
 
// TAP reset action : definition
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
 
#ifndef TAP_RESET_ACTION__H
#define TAP_RESET_ACTION__H
 
#include "TapAction.h"
#include "TapStateMachine.h"
 
 
//! Class to represent a TAP reset action.
 
//! This can be very simple, since it reuses the parent class method to do the
//! reset.
 
class TapActionReset
: public TapAction
{
public:
 
// Constructor
TapActionReset (sc_core::sc_event *_doneEvent);
 
 
protected:
 
// Process the action for reset
bool process (TapStateMachine *tapStateMachine,
bool &tdi,
bool tdo,
bool &tms);
 
 
private:
 
//!< Flag to mark first call to process method
bool firstTime;
 
}; // TapActionReset
 
#endif // TAP_RESET_ACTION__H
/include/JtagDriverSC.h
0,0 → 1,138
// ----------------------------------------------------------------------------
 
// SystemC JTAG driver header
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: JtagDriverSC.h 317 2009-02-22 19:52:12Z jeremy $
 
#ifndef JTAG_DRIVER_SC__H
#define JTAG_DRIVER_SC__H
 
#include <stdint.h>
 
#include "systemc"
 
#include "jtagsc.h"
 
 
//! Module providing TAP requests to JTAG
 
//! Provides a queue of requests to the JTAG interface. Requests are at the
//! level of TAP actions for reset, DR-Scan or IR-Scan.
 
class JtagDriverSC
: public sc_core::sc_module
{
public:
 
// Constructor
JtagDriverSC (sc_core::sc_module_name name,
sc_core::sc_fifo<TapAction *> *_tapActionQueue);
 
private:
 
// JTAG instructions
static const uint32_t CHAIN_SELECT_IR = 0x3; //!< Chain Select instruction
static const uint32_t DEBUG_IR = 0x8; //!< Debug instruction
 
// JTAG register lengths (excluding CRC)
static const int JTAG_IR_LEN = 4; //!< JTAG instr reg length
static const int CHAIN_DR_LEN = 4; //!< Length of DR (excl CRC)
static const int RISC_DEBUG_DR_LEN = 65; //!< Length of DR (excl CRC)
static const int REGISTER_DR_LEN = 38; //!< Length of DR (excl CRC)
static const int WISHBONE_DR_LEN = 65; //!< Length of DR (excl CRC)
 
// JTAG register address masks
static const uint32_t RISC_DEBUG_ADDR_MASK = 0xffffffff; //!< Mask for addr
static const uint32_t REGISTER_ADDR_MASK = 0x0000001f; //!< Mask for addr
static const uint32_t WISHBONE_ADDR_MASK = 0xffffffff; //!< Mask for addr
 
// JTAG register R/W bit
static const uint64_t RISC_DEBUG_RW = 0x100000000ULL; //!< R/W bit mask
static const uint64_t REGISTER_RW = 0x000000020ULL; //!< R/W bit mask
static const uint64_t WISHBONE_RW = 0x100000000ULL; //!< R/W bit mask
 
// JTAG register data field offsets
static const int RISC_DEBUG_DATA_OFF = 33; //!< Offset to data field
static const int REGISTER_DATA_OFF = 6; //!< Offset to data field
static const int WISHBONE_DATA_OFF = 33; //!< Offset to data field
 
//! JTAG register data field sizes (all the same)
static const int DR_DATA_LEN = 32;
 
//! CRC length
static const int CRC_LEN = 8;
 
// OpenRISC 1000 scan chains
static const int OR1K_SC_UNDEF = -1; //!< Undefined OR1K scan chain
static const int OR1K_SC_RISC_DEBUG = 1; //!< for access to SPRs
static const int OR1K_SC_REGISTER = 4; //!< to stall/reset CPU
static const int OR1K_SC_WISHBONE = 5; //!< for memory access
 
//! Register addresses for the REGISTER scan chain
static const uint8_t OR1K_RSC_RISCOP = 0x04; //!< Used to reset/stall CPU
 
// Bits for the RISCOP register
static const uint32_t RISCOP_STALL = 0x00000001; //!< Stall the CPU
static const uint32_t RISCOP_RESET = 0x00000002; //!< Reset the CPU
 
//! The JTAG fifo we queue on
sc_core::sc_fifo<TapAction *> *tapActionQueue;
 
//! The currently selected scan chain
int currentScanChain;
 
// SystemC thread to queue actions
void queueActions ();
 
// Or1k JTAG actions
void reset ();
void selectChain (int chain);
uint32_t readReg (uint32_t addr);
uint32_t readReg1 (uint32_t addr,
int bitSizeNoCrc);
uint32_t readReg1 (uint64_t *dRegArray,
uint32_t addr,
int bitSizeNoCrc);
void writeReg (uint32_t addr,
uint32_t data);
// Utilities to compute CRC-8 the OpenRISC way. Versions for "big" and
// "small" numbers.
uint8_t crc8 (uint64_t data,
int size);
uint8_t crc8 (uint64_t *dataArray,
int size);
 
// Utilities to insert and extract bit strings from vectors
void insertBits (uint64_t str,
int strLen,
uint64_t *array,
int startBit);
uint64_t extractBits (uint64_t *array,
int startBit,
int strLen);
 
}; // JtagDriverSC ()
 
#endif // JTAG_DRIVER_SC__H
/include/OrpsocAccess.h
38,7 → 38,10
class Vorpsoc_top_or1200_except;
class Vorpsoc_top_or1200_sprs;
class Vorpsoc_top_or1200_dpram;
class Vorpsoc_top_ram_wb_sc_sw__D20_A18_M800000;
// Main memory access class - will change if main memory size or other parameters change
class Vorpsoc_top_ram_wb_sc_sw__D20_A19_M800000;
// SoC Arbiter class - will also change if any modifications to bus architecture
class Vorpsoc_top_wb_conbus_top__pi1;
 
 
//! Access functions to the Verilator model
79,6 → 82,22
// Trigger a $readmemh for the RAM array
void do_ram_readmemh (void);
 
// Arbiter access functions
uint8_t getWbArbGrant ();
// Master Signal Access functions
uint32_t getWbArbMastDatI (uint32_t mast_num);
uint32_t getWbArbMastDatO (uint32_t mast_num);
uint32_t getWbArbMastAdrI (uint32_t mast_num);
uint8_t getWbArbMastSelI (uint32_t mast_num);
uint8_t getWbArbMastSlaveSelDecoded (uint32_t mast_num);
bool getWbArbMastWeI (uint32_t mast_num);
bool getWbArbMastCycI (uint32_t mast_num);
bool getWbArbMastStbI (uint32_t mast_num);
bool getWbArbMastAckO (uint32_t mast_num);
bool getWbArbMastErrO (uint32_t mast_num);
 
 
private:
 
// Pointers to modules with accessor functions
86,7 → 105,9
Vorpsoc_top_or1200_except *or1200_except;
Vorpsoc_top_or1200_sprs *or1200_sprs;
Vorpsoc_top_or1200_dpram *rf_a;
/*Vorpsoc_top_ram_wb_sc_sw*/Vorpsoc_top_ram_wb_sc_sw__D20_A18_M800000 *ram_wb_sc_sw;
/*Vorpsoc_top_ram_wb_sc_sw*/Vorpsoc_top_ram_wb_sc_sw__D20_A19_M800000 *ram_wb_sc_sw;
// Arbiter
Vorpsoc_top_wb_conbus_top__pi1 *wb_arbiter;
 
}; // OrpsocAccess ()
 
/include/SprCache.h
0,0 → 1,88
// ----------------------------------------------------------------------------
 
// Debug Unit SPR cache: definition
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// 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.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: SprCache.h 331 2009-03-12 17:01:48Z jeremy $
 
#ifndef SPR_CACHE__H
#define SPR_CACHE__H
 
#include <stdint.h>
 
 
//-----------------------------------------------------------------------------
//! Module for cacheing SPR accesses by the debug unit
 
//! SPR reads and writes through the Debug Unit via JTAG are time
//! consuming - of the order of 1000 CPU clock cycles. However when the
//! processor is stalled the values cannot change, other than through the
//! debug unit, so it makes sense to cache values.
 
//! @note It is not strictly true that SPRs do not change. If the NPC is
//! written, it flushes the pipeline, and subsequent reads will return
//! zero until the processor is unstalled and the pipeline has
//! refilled. However for our purposes, it is convenient to return the
//! value written into the NPC in such circumstances.
//!
//! The cache is represented as a closed hash table, which is generally
//! allowed to be no more than 70% full (however NPC is always
//! cacheable). The hash function is a simple modulo function, stepping
//! forward to the first free slot. This works because there is no function to
//! delete an entry - just to clear the whole table, so holes cannot appear.
//-----------------------------------------------------------------------------
class SprCache
{
public:
 
// Constructor and destructor
SprCache (int _tableSize = 257);
~SprCache ();
 
// Functions
void clear ();
void write (uint16_t sprNum,
uint32_t value,
bool force);
bool read (uint16_t sprNum,
uint32_t &value);
 
private:
 
//! The size of the hash table
int tableSize;
 
//! Maximum amount of cache left to use, before cacheing is rejected.
int maxToUse;
 
// The cache, keyed by sprNum. Done as two parallel vectors,
// allowing unambiguous clearing by use of memset for efficiency.
bool *sprIsValid;
uint16_t *sprKeyNum;
uint32_t *sprValue;
 
 
}; // SprCache ()
 
#endif // SPR_CACHE__H
/src/Utils.cpp
0,0 → 1,293
// ----------------------------------------------------------------------------
 
// GDB Server Utilties: implementation
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: Utils.cpp 324 2009-03-07 09:42:52Z jeremy $
 
#include "Utils.h"
 
 
//-----------------------------------------------------------------------------
//!Utility to give the value of a hex char
 
//! @param[in] ch A character representing a hexadecimal digit. Done as -1,
//! for consistency with other character routines, which can
//! use -1 as EOF.
 
//! @return The value of the hex character, or -1 if the character is
//! invalid.
//-----------------------------------------------------------------------------
uint8_t
Utils::char2Hex (int c)
{
return ((c >= 'a') && (c <= 'f')) ? c - 'a' + 10 :
((c >= '0') && (c <= '9')) ? c - '0' :
((c >= 'A') && (c <= 'F')) ? c - 'A' + 10 : -1;
 
} // char2Hex ()
 
 
//-----------------------------------------------------------------------------
//! Utility mapping a value to hex character
 
//! @param[in] d A hexadecimal digit. Any non-hex digit returns a NULL char
//-----------------------------------------------------------------------------
const char
Utils::hex2Char (uint8_t d)
{
static const char map [] = "0123456789abcdef"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
 
return map[d];
 
} // hex2Char ()
 
 
//-----------------------------------------------------------------------------
//! Convert a register to a hex digit string
 
//! The supplied 32-bit value is converted to an 8 digit hex string. The
//! string is null terminated for convenience. The hex string follows the
//! universal printing convention: most significant digit on the left.
 
//! @param[in] val The value to convert
//! @param[out] buf The buffer for the text string
//-----------------------------------------------------------------------------
void
Utils::reg2Hex (uint32_t val,
char *buf)
{
for (int n = 7; n >= 0; n--)
{
buf[n] = hex2Char (val & 0xf);
val /= 16;
}
 
buf[8] = 0; // Useful to terminate as string
 
} // reg2hex ()
 
 
//-----------------------------------------------------------------------------
//! Convert a hex digit string to a register value
 
//! The supplied 8 digit hex string follows the universal printing convention:
//! most significant digit on the left. It is converted to a 32-bit value.
 
//! @param[in] buf The buffer with the hex string
 
//! @return The value to convert
//-----------------------------------------------------------------------------
uint32_t
Utils::hex2Reg (char *buf)
{
uint32_t val = 0; // The result
 
for (int n = 0; n < 8; n++)
{
val = val * 16 + char2Hex (buf[n]);
}
 
return val;
 
} // hex2reg ()
 
 
//-----------------------------------------------------------------------------
//! Convert an ASCII character string to pairs of hex digits
 
//! Both source and destination are null terminated.
 
//! @param[out] dest Buffer to store the hex digit pairs (null terminated)
//! @param[in] src The ASCII string (null terminated) */
//-----------------------------------------------------------------------------
void
Utils::ascii2Hex (char *dest,
char *src)
{
int i;
 
// Step through converting the source string
for (i = 0; src[i] != '\0'; i++)
{
char ch = src[i];
 
dest[i * 2] = hex2Char(ch >> 4 & 0xf);
dest[i * 2 + 1] = hex2Char(ch & 0xf);
}
 
dest[i * 2] = '\0';
} // ascii2hex ()
 
 
//-----------------------------------------------------------------------------
//! Convert pairs of hex digits to an ASCII character string
 
//! Both source and destination are null terminated.
 
//! @param[out] dest The ASCII string (null terminated)
//! @param[in] src Buffer holding the hex digit pairs (null terminated)
//-----------------------------------------------------------------------------
void
Utils::hex2Ascii (char *dest,
char *src)
{
int i;
 
// Step through convering the source hex digit pairs
for (i = 0; src[i * 2] != '\0' && src[i * 2 + 1] != '\0'; i++)
{
dest[i] = ((char2Hex (src[i * 2]) & 0xf) << 4) |
(char2Hex (src[i * 2 + 1]) & 0xf);
}
 
dest[i] = '\0';
 
} // hex2ascii ()
 
 
//-----------------------------------------------------------------------------
//! "Unescape" RSP binary data
 
//! '#', '$' and '}' are escaped by preceding them by '}' and oring with 0x20.
 
//! This function reverses that, modifying the data in place.
 
//! @param[in] buf The array of bytes to convert
//! @para[in] len The number of bytes to be converted
 
//! @return The number of bytes AFTER conversion
//-----------------------------------------------------------------------------
int
Utils::rspUnescape (char *buf,
int len)
{
int fromOffset = 0; // Offset to source char
int toOffset = 0; // Offset to dest char
 
while (fromOffset < len)
{
// Is it escaped
if ( '}' == buf[fromOffset])
{
fromOffset++;
buf[toOffset] = buf[fromOffset] ^ 0x20;
}
else
{
buf[toOffset] = buf[fromOffset];
}
 
fromOffset++;
toOffset++;
}
 
return toOffset;
 
} // rspUnescape () */
 
 
//-----------------------------------------------------------------------------
//! Convert 32-bit value from host to target endianness
 
//! The target endianness is determined by the #define of TARGET_BIG_ENDIAN and
//! TARGET_LITTLE_ENDIAN. Not definining either is a compile time error.
 
//! @param[in] hostVal The value in host endianness
 
//! @return The value in target endianness
//-----------------------------------------------------------------------------
uint32_t
Utils::htotl (uint32_t hostVal)
{
uint8_t targetBytes[4];
 
#ifdef TARGET_BIG_ENDIAN
targetBytes[0] = hostVal / 256 / 256 / 256;
targetBytes[1] = hostVal / 256 / 256;
targetBytes[2] = hostVal / 256;
targetBytes[3] = hostVal;
#elif defined TARGET_LITTLE_ENDIAN
targetBytes[0] = hostVal;
targetBytes[1] = hostVal / 256;
targetBytes[2] = hostVal / 256 / 256;
targetBytes[3] = hostVal / 256 / 256 / 256;
#else
#error Must specify TARGET_BIG_ENDIAN or TARGET_LITTLE_ENDIAN
#endif
 
return *((uint32_t *)targetBytes);
 
} // htotl ()
 
 
//-----------------------------------------------------------------------------
//! Convert 32-bit value from target to host endianness
 
//! The target endianness is determined by the #define of TARGET_BIG_ENDIAN and
//! TARGET_LITTLE_ENDIAN. Not definining either is a compile time error.
 
//! @param[in] targetVal The value in target endianness
 
//! @return The value in target endianness
//-----------------------------------------------------------------------------
uint32_t
Utils::ttohl (uint32_t targetVal)
{
uint8_t *targetBytes = (uint8_t *)(&targetVal);
uint32_t hostVal;
 
#ifdef TARGET_BIG_ENDIAN
hostVal = targetBytes[0];
hostVal = hostVal * 256 + targetBytes[1];
hostVal = hostVal * 256 + targetBytes[2];
hostVal = hostVal * 256 + targetBytes[3];
#elif defined TARGET_LITTLE_ENDIAN
hostVal = targetBytes[3];
hostVal = hostVal * 256 + targetBytes[2];
hostVal = hostVal * 256 + targetBytes[1];
hostVal = hostVal * 256 + targetBytes[0];
#else
#error Must specify TARGET_BIG_ENDIAN or TARGET_LITTLE_ENDIAN
#endif
 
return hostVal;
 
} // ttohl ()
/src/MemCache.cpp
0,0 → 1,120
// ----------------------------------------------------------------------------
 
// Debug Unit memory cache: implementation
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// 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.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: MemCache.cpp 326 2009-03-07 16:47:31Z jeremy $
 
#include <cstring>
 
#include "MemCache.h"
 
 
//! Constructor
 
//! Allocate a closed hash table of the specified size and clear it.
 
//! @param[in] _tableSize The desire hash table size. A prime number is
//! recommended.
 
MemCache::MemCache (int _tableSize) :
tableSize (_tableSize)
{
tabIsValid = new bool [tableSize];
tabKeyAddr = new uint32_t [tableSize];
tabValue = new uint32_t [tableSize];
 
clear ();
 
} // MemCache ()
 
 
//! Destructor
 
//! Free the hash table arrays
 
MemCache::~MemCache ()
{
delete [] tabIsValid;
delete [] tabKeyAddr;
delete [] tabValue;
 
} // ~MemCache ()
 
 
//! Empty the hash table
 
//! Only need to worry about the validity field
void
MemCache::clear ()
{
memset (tabIsValid, false, sizeof (tabIsValid));
 
} // clear ()
 
 
//! Write a new value into the hash table
 
//! Will trash anything already there.
 
//! @param[in] addr The address being written to
//! @param[in] value The value to write
void
MemCache::write (uint32_t addr,
uint32_t value)
{
int keyAddr = addr % tableSize;
 
tabIsValid[keyAddr] = true;
tabKeyAddr[keyAddr] = addr;
tabValue[keyAddr] = value;
 
} // write ()
 
 
//! Try to read a value from the hash table
 
//! The entry must be valid and the address must match
 
//! @param[in] addr The address being read from
//! @param[out] value The value read, if there was one there
 
//! @return True if the value was found in the hash table
 
bool
MemCache::read (uint32_t addr,
uint32_t &value)
{
int keyAddr = addr % tableSize;
if (tabIsValid[keyAddr] & (tabKeyAddr[keyAddr] == addr))
{
value = tabValue[keyAddr];
return true;
}
else
{
return false;
}
} // read ()
/src/Modules.make
31,6 → 31,8
CXXFLAGS += $(VLT_CPPFLAGS)
endif
 
CPPFLAGS += -DTARGET_BIG_ENDIAN
 
CXX ?= g++
#PROF_OPTS ?= -fbranch-probabilities -fvpt -funroll-loops -fpeel-loops -ftracer -O3
OPT_ALL ?= $(OPT_SLOW) $(OPT_FAST) $(OPT)
40,8 → 42,22
INCDIRS = -I$(SYSTEMC)/include -I$(SYSC_INC_DIR)
 
# Local objects
OBJS = Or1200MonitorSC.o \
ResetSC.o \
OBJS = DebugUnitSC.o \
GdbServerSC.o \
JtagSC.o \
TapAction.o \
TapActionDRScan.o \
TapActionIRScan.o \
TapActionReset.o \
TapStateMachine.o \
MemCache.o \
MpHash.o \
Or1200MonitorSC.o \
ResetSC.o \
RspConnection.o \
RspPacket.o \
SprCache.o \
Utils.o \
UartSC.o
LIB = libmodules.a
 
/src/MemoryLoad.cpp
702,13 → 702,15
 
 
if (ELF_LONG_H (elf_spnt->sh_name) && s_str)
PRINTF ("Section: %s,", &s_str[ELF_LONG_H (elf_spnt->sh_name)]);
//PRINTF ("Section: %s,", &s_str[ELF_LONG_H (elf_spnt->sh_name)]);
printf("* Section: %s,", &s_str[ELF_LONG_H (elf_spnt->sh_name)]);
else
PRINTF ("Section: noname,");
PRINTF (" vaddr: 0x%.8lx,", ELF_LONG_H (elf_spnt->sh_addr));
PRINTF (" paddr: 0x%" PRIx32, padd);
PRINTF (" offset: 0x%.8lx,", ELF_LONG_H (elf_spnt->sh_offset));
PRINTF (" size: 0x%.8lx\n", ELF_LONG_H (elf_spnt->sh_size));
//PRINTF ("Section: noname,");
printf ("* Section: noname,");
printf ("* vaddr: 0x%.8lx,", ELF_LONG_H (elf_spnt->sh_addr));
printf ("* paddr: 0x%" PRIx32, padd);
printf ("* offset: 0x%.8lx,", ELF_LONG_H (elf_spnt->sh_offset));
printf ("* size: 0x%.8lx\n", ELF_LONG_H (elf_spnt->sh_size));
 
freemem = padd;
sectsize = ELF_LONG_H (elf_spnt->sh_size);
/src/GdbServerSC.cpp
0,0 → 1,1921
// ----------------------------------------------------------------------------
 
// SystemC GDB RSP server: implementation
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
// Contributor Julius Baxter <julius@orsoc.se>
 
// 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.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
#include <iostream>
#include <iomanip>
 
#include "GdbServerSC.h"
#include "Utils.h"
 
#include <errno.h>
#include <fcntl.h>
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::dec;
using std::endl;
using std::hex;
 
using sc_core::sc_fifo;
using sc_core::sc_module_name;
using sc_core::sc_stop;
using sc_core::sc_time;
 
 
SC_HAS_PROCESS (GdbServerSC);
 
//-----------------------------------------------------------------------------
//! Constructor for the GDB RSP server.
 
//! 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.
 
//! The current scan chain is marked as undefined.
 
//! This makes use of the Embecosm cycle accurate SystemC JTAG interface.
 
//! @see Embecosm Application Note 5 "Using JTAG with SystemC: Implementation
//! of a Cycle Accurate Interface"
//! (http://www.embecosm.com/download/ean5.html)
 
//! @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
//! the exception registers and redirect through the trap vector.
 
//! @param[in] name Name of this module, passed to the parent
//! constructor.
//! @param[in] _tapActionQueue Pointer to fifo of actions to be performed by
//! the JTAG interface
//-----------------------------------------------------------------------------
GdbServerSC::GdbServerSC (sc_module_name name,
uint32_t _flashStart,
uint32_t _flashEnd,
int rspPort,
sc_fifo<TapAction *> *tapActionQueue) :
sc_module (name),
flashStart (_flashStart),
flashEnd (_flashEnd)
{
pkt = new RspPacket (RSP_PKT_MAX);
rsp = new RspConnection (rspPort);
debugUnit = new DebugUnitSC ("debug-unit", tapActionQueue);
mpHash = new MpHash ();
 
/* Setup the pipes between or1200 monitor module and GDB stub */
pipe(monitor_to_gdb_pipe[0]);
pipe(monitor_to_gdb_pipe[1]);
// Set non-blocking reads
#ifdef O_NONBLOCK /* The POSIX way */
fcntl (monitor_to_gdb_pipe[0][0], F_SETFL, O_NONBLOCK);
fcntl (monitor_to_gdb_pipe[1][0], F_SETFL, O_NONBLOCK);
#elif defined (O_NDELAY)
fcntl (monitor_to_gdb_pipe[0][0], F_SETFL, O_NDELAY);
fcntl (monitor_to_gdb_pipe[1][0], F_SETFL, O_NDELAY);
#endif /* O_NONBLOCK */
 
SC_THREAD (rspServer);
 
} // GdbServerSC ()
 
 
//-----------------------------------------------------------------------------
//! Destructor
 
//! Free up data structures
//-----------------------------------------------------------------------------
GdbServerSC::~GdbServerSC ()
{
delete mpHash;
delete debugUnit;
delete rsp;
delete pkt;
 
} // ~GdbServerSC
 
 
//-----------------------------------------------------------------------------
//! SystemC thread to listen for RSP requests
 
//! JTAG actions will be queued as appropriate. Runs forever
 
//! 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
//! the PPC is still in flash memory.
 
//! Have to use a thread, since we will end up waiting for actions to
//! complete.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspServer ()
{
// 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
// at reset PPC is zero, and would trigger a false positive.
debugUnit->resetDebugUnit ();
rsp_sigval = TARGET_SIGNAL_NONE;
/*
uint32_t npc;
do
{
npc = debugUnit->readSpr (SPR_NPC);
}
while ((flashStart <= npc) && (npc <= flashEnd));
*/
debugUnit->stall ();
targetStopped = true;
// Make sure we are connected.
while (!rsp->isConnected ())
{
// Reconnect and stall the processor on a new connection
if (!rsp->rspConnect ())
{
// Serious failure. Must abort execution.
cerr << "*** Unable to continue: ABORTING" << endl;
sc_stop ();
}
// Stall the processor until we get a command to handle.
if (!debugUnit->isStalled ())
{
debugUnit->stall ();
}
targetStopped = true; // Processor now not running
}
 
// Loop processing commands forever
while (true)
{
if (!rsp->isConnected())
{
sc_stop ();
return;
}
// Wait until the target has stopped. In this simplified implementation,
// the only reasons for stopping are hitting a breakpoint (l.trap),
// hardware single stepping or hitting a non-breakpoint l.trap. This
// last is not cleanly handled at the moment (we ought to redirect the
// restart through the trap exception vector).
while (!targetStopped)
{
 
/* First check to see if the or1200 monitor module wants us to stall*/
if (checkMonitorPipe())
break;
rspCheckForException();
if (debugUnit->isStalled())
{
targetStopped = true;
 
// If it's a breakpoint, then we need to back up one
// instruction, so on restart we execute the actual
// instruction.
uint32_t ppc = debugUnit->readSpr (SPR_PPC);
 
if (NULL != mpHash->lookup (BP_MEMORY, ppc) && rsp_sigval == TARGET_SIGNAL_TRAP)
{
writeNpc (ppc);
}
 
// Tell the client we've stopped.
rspReportException ();
}
else if (rsp->rspSocketPeek() > 0)
{
if (rsp->rspSocketPeek() == 0x03) // ETX, end of text control char
{
// Got an interrupt command from GDB, this function should
// pull the packet off the socket and stall the processor.
// and then send a stop reply packet with signal
// TARGET_SIGNAL_NONE.
rspInterrupt();
targetStopped = true; // Processor now not running
}
}
}
 
// Get a RSP client request
rspClientRequest ();
}
} // rspServer ()
 
 
//-----------------------------------------------------------------------------
//! Deal with a request from the GDB client session
 
//! In general, apart from the simplest requests, this function replies on
//! other functions to implement the functionality.
 
//! @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
//! reply.
 
//! @todo Is this the implementation of the 'D' packet really the intended
//! meaning? Or does it just mean that only vAttach will be recognized
//! after this?
 
//! @param[in] pkt The received RSP packet
//-----------------------------------------------------------------------------
void
GdbServerSC::rspClientRequest ()
{
if (!rsp->getPkt (pkt))
{
rsp->rspClose (); // Comms failure
return;
}
//cerr << "rspClientRequest: " << pkt->data/*[0]*/ << endl;
switch (pkt->data[0])
{
case '!':
// Request for extended remote mode
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
 
case '?':
// Return last signal ID
rspReportException ();
return;
 
case 'A':
// Initialization of argv not supported
cerr << "Warning: RSP 'A' packet not supported: ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
 
case 'b':
// Setting baud rate is deprecated
cerr << "Warning: RSP 'b' packet is deprecated and not "
<< "supported: ignored" << endl;
return;
 
case 'B':
// Breakpoints should be set using Z packets
cerr << "Warning: RSP 'B' packet is deprecated (use 'Z'/'z' "
<< "packets instead): ignored" << endl;
return;
 
case 'c':
// Continue
rspContinue (EXCEPT_NONE);
return;
 
case 'C':
// Continue with signal (in the packet)
rspContinue ();
return;
 
case 'd':
// Disable debug using a general query
cerr << "Warning: RSP 'd' packet is deprecated (define a 'Q' "
<< "packet instead: ignored" << endl;
return;
 
case 'D':
// Detach GDB. Do this by closing the client. The rules say that
// execution should continue, so unstall the processor.
pkt->packStr("OK");
rsp->putPkt (pkt);
rsp->rspClose ();
//debugUnit->unstall ();
return;
 
case 'F':
// File I/O is not currently supported
cerr << "Warning: RSP file I/O not currently supported: 'F' "
<< "packet ignored" << endl;
return;
 
case 'g':
rspReadAllRegs ();
return;
 
case 'G':
rspWriteAllRegs ();
return;
case 'H':
// Set the thread number of subsequent operations. For now ignore
// silently and just reply "OK"
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
 
case 'i':
case 'I':
// Single cycle step not currently supported. Mark the target as
// 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.
cerr << "Warning: RSP cycle stepping not supported: target "
<< "stopped immediately" << endl;
targetStopped = false;
return;
 
case 'k':
// Kill request. Do nothing for now.
return;
 
case 'm':
// Read memory (symbolic)
rspReadMem ();
return;
 
case 'M':
// Write memory (symbolic)
rspWriteMem ();
return;
 
case 'p':
// Read a register
rspReadReg ();
return;
 
case 'P':
// Write a register
rspWriteReg ();
return;
 
case 'q':
// Any one of a number of query packets
rspQuery ();
return;
 
case 'Q':
// Any one of a number of set packets
rspSet ();
return;
 
case 'r':
// Reset the system. Deprecated (use 'R' instead)
cerr << "Warning: RSP 'r' packet is deprecated (use 'R' "
<< "packet instead): ignored" << endl;
return;
 
case 'R':
// Restart the program being debugged.
rspRestart ();
return;
 
case 's':
// Single step one machine instruction.
rspStep (EXCEPT_NONE);
return;
 
case 'S':
// Single step one machine instruction.
rspStep ();
return;
 
case 't':
// Search. This is not well defined in the manual and for now we don't
// support it. No response is defined.
cerr << "Warning: RSP 't' packet not supported: ignored"
<< endl;
return;
 
case 'T':
// Is the thread alive. We are bare metal, so don't have a thread
// context. The answer is always "OK".
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
 
case 'v':
// Any one of a number of packets to control execution
rspVpkt ();
return;
 
case 'X':
// Write memory (binary)
rspWriteMemBin ();
return;
 
case 'z':
// Remove a breakpoint/watchpoint.
rspRemoveMatchpoint ();
return;
 
case 'Z':
// Insert a breakpoint/watchpoint.
rspInsertMatchpoint ();
return;
 
default:
// Unknown commands are ignored
cerr << "Warning: Unknown RSP request" << pkt->data << endl;
return;
}
} // rspClientRequest ()
 
 
 
//-----------------------------------------------------------------------------
//! Check if processor is stalled. If it is, read the DRR and return the
//! target signal code.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspCheckForException()
{
 
uint32_t drr;
if (!debugUnit->isStalled())
{
// Processor not stalled. Just return;
return;
}
switch ((debugUnit->readSpr(SPR_DRR)&0xffffffff))
{
case SPR_DRR_RSTE: rsp_sigval = TARGET_SIGNAL_PWR; break;
case SPR_DRR_BUSEE: rsp_sigval = TARGET_SIGNAL_BUS; break;
case SPR_DRR_DPFE: 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_AE: rsp_sigval = TARGET_SIGNAL_BUS; break;
case SPR_DRR_IIE: rsp_sigval = TARGET_SIGNAL_ILL; break;
case SPR_DRR_IE: rsp_sigval = TARGET_SIGNAL_INT; break;
case SPR_DRR_DME: 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_SCE: rsp_sigval = TARGET_SIGNAL_USR2; break;
case SPR_DRR_FPE: rsp_sigval = TARGET_SIGNAL_FPE; break;
case SPR_DRR_TE: rsp_sigval = TARGET_SIGNAL_TRAP; break;
default:
// This must be the case of single step (which does not set DRR)
rsp_sigval = TARGET_SIGNAL_TRAP; break;
}
 
return;
}
 
//-----------------------------------------------------------------------------
//! Send a packet acknowledging an exception has occurred
 
//! The only signal we ever see in this implementation is TRAP.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspReportException ()
{
// Construct a signal received packet
pkt->data[0] = 'S';
pkt->data[1] = Utils::hex2Char (rsp_sigval >> 4);
pkt->data[2] = Utils::hex2Char (rsp_sigval % 16);
pkt->data[3] = '\0';
pkt->setLen (strlen (pkt->data));
 
rsp->putPkt (pkt);
 
} // rspReportException ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP continue request
 
//! 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.
 
//! At present other exceptions are not supported
 
//! @param[in] except The OpenRISC 1000 exception to use
//-----------------------------------------------------------------------------
void
GdbServerSC::rspContinue (uint32_t except)
{
uint32_t addr; // Address to continue from, if any
 
// Reject all except 'c' packets
if ('c' != pkt->data[0])
{
cerr << "Warning: Continue with signal not currently supported: "
<< "ignored" << endl;
return;
}
 
// Get an address if we have one
if (0 == strcmp ("c", pkt->data))
{
addr = readNpc (); // Default uses current NPC
}
else if (1 != sscanf (pkt->data, "c%lx", &addr))
{
cerr << "Warning: RSP continue address " << pkt->data
<< " not recognized: ignored" << endl;
addr = readNpc (); // Default uses current NPC
}
 
rspContinue (addr, EXCEPT_NONE);
 
} // rspContinue ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP continue with signal request
 
//! @todo Currently does nothing. Will use the underlying generic continue
//! function.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspContinue ()
{
cerr << "RSP continue with signal '" << pkt->data
<< "' received" << endl;
 
} // rspContinue ()
 
 
//-----------------------------------------------------------------------------
//! Generic processing of a continue request
 
//! The signal may be EXCEPT_NONE if there is no exception to be
//! handled. Currently the exception is ignored.
 
//! The single step flag is cleared in the debug registers and then the
//! processor is unstalled.
 
//! @param[in] addr Address from which to step
//! @param[in] except The exception to use (if any)
//-----------------------------------------------------------------------------
void
GdbServerSC::rspContinue (uint32_t addr,
uint32_t except)
{
// Set the address as the value of the next program counter
writeNpc (addr);
/*
// If we're continuing from a breakpoint, replace that instruction in the memory
// ... actually no, I was wrong about this.
if (NULL != mpHash->lookup (BP_MEMORY, addr) && rsp_sigval == TARGET_SIGNAL_TRAP)
{
MpEntry *entry = mpHash->lookup (BP_MEMORY, addr);
debugUnit->writeMem32(entry->addr, entry->instr);
}
*/
// Clear Debug Reason Register and watchpoint break generation in Debug Mode
// Register 2 for watchpoints that we triggered to stop this time.
debugUnit->writeSpr (SPR_DRR, 0);
if (rsp_sigval == TARGET_SIGNAL_TRAP)
{
/*
Disable last trap generation on watchpoint if this is why we stopped
last time.
*/
uint32_t temp_dmr2 = debugUnit->readSpr (SPR_DMR2);
if (temp_dmr2 & SPR_DMR2_WBS)
{
/*
One of these breakpoints is responsible for our stopping, so
disable it this time we start. GDB will send a packet re-enabling
it next time we continue.
*/
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
// be handled by the debug unit in the Debug Stop Register
debugUnit->andSpr (SPR_DMR1, ~SPR_DMR1_ST);
debugUnit->orSpr ( SPR_DSR, SPR_DSR_TE);
 
// Unstall the processor. Note the GDB client is now waiting for a reply,
// which it will get as soon as the processor stalls again.
debugUnit->unstall ();
targetStopped = false;
 
} // rspContinue ()
 
 
 
//------------------------------------------------------------------------------
//!Handle an interrupt from GDB
 
//! Detect an interrupt from GDB and stall the processor
//------------------------------------------------------------------------------
void
GdbServerSC::rspInterrupt()
{
unsigned char c;
 
c = rsp->getRspChar();
if (c < 0)
{
// Had issues, just return
return;
}
// 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
// things go back to normal...
if (c != 0x03)
{
cerr << "* Warning: Interrupt character expected but not found on socket" << endl;
return;
}
// Otherwise, it's an interrupt packet, stall the processor, and upon return
// to the main handle_rsp() loop, it will inform GDB.
 
debugUnit->stall ();
 
// Send a stop reply response, manually set rsp.sigval to TARGET_SIGNAL_NONE
rsp_sigval = TARGET_SIGNAL_NONE;
rspReportException();
 
return;
}
 
//-----------------------------------------------------------------------------
//! Handle a RSP read all registers request
 
//! 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
//! returned as a sequence of bytes in target endian order.
 
//! Each byte is packed as a pair of hex digits.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspReadAllRegs ()
{
// The GPRs
for (int r = 0; r < max_gprs; r++)
{
Utils::reg2Hex (readGpr (r), &(pkt->data[r * 8]));
}
 
// PPC, NPC and SR
Utils::reg2Hex (debugUnit->readSpr (SPR_PPC), &(pkt->data[PPC_REGNUM * 8]));
Utils::reg2Hex (readNpc (), &(pkt->data[NPC_REGNUM * 8]));
Utils::reg2Hex (debugUnit->readSpr (SPR_SR), &(pkt->data[SR_REGNUM * 8]));
 
// Finalize the packet and send it
pkt->data[NUM_REGS * 8] = 0;
pkt->setLen (NUM_REGS * 8);
rsp->putPkt (pkt);
 
} // rspReadAllRegs ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP write all registers request
 
//! 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
//! supplied as a sequence of bytes in target endian order.
 
//! Each byte is packed as a pair of hex digits.
 
//! @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
//! of data is present. The result is always "OK".
//-----------------------------------------------------------------------------
void
GdbServerSC::rspWriteAllRegs ()
{
// The GPRs
for (int r = 0; r < max_gprs; r++)
{
writeGpr (r, Utils::hex2Reg (&(pkt->data[r * 8])));
}
 
// PPC, NPC and SR
debugUnit->writeSpr (SPR_PPC, Utils::hex2Reg (&(pkt->data[PPC_REGNUM * 8])));
debugUnit->writeSpr (SPR_SR, Utils::hex2Reg (&(pkt->data[SR_REGNUM * 8])));
writeNpc ( Utils::hex2Reg (&(pkt->data[NPC_REGNUM * 8])));
 
// Acknowledge (always OK for now).
pkt->packStr ("OK");
rsp->putPkt (pkt);
 
} // rspWriteAllRegs ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP read memory (symbolic) request
 
//! Syntax is:
 
//! m<addr>,<length>:
 
//! The response is the bytes, lowest address first, encoded as pairs of hex
//! digits.
 
//! The length given is the number of bytes to be read.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspReadMem ()
{
unsigned int addr; // Where to read the memory
int len; // Number of bytes to read
int off; // Offset into the memory
 
if (2 != sscanf (pkt->data, "m%x,%x:", &addr, &len))
{
cerr << "Warning: Failed to recognize RSP read memory command: "
<< pkt->data << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// Make sure we won't overflow the buffer (2 chars per byte)
if ((len * 2) >= pkt->getBufSize())
{
cerr << "Warning: Memory read " << pkt->data
<< " too large for RSP packet: truncated" << endl;
len = (pkt->getBufSize() - 1) / 2;
}
//cerr << "rspReadMem: " << len << " bytes@0x"<< hex << addr << endl;
// Refill the buffer with the reply
for (off = 0; off < len; off++)
{
unsigned char ch = debugUnit->readMem8 (addr + off);
 
pkt->data[off * 2] = Utils::hex2Char(ch >> 4);
pkt->data[off * 2 + 1] = Utils::hex2Char(ch & 0xf);
}
 
pkt->data[off * 2] = '\0'; // End of string
pkt->setLen (strlen (pkt->data));
rsp->putPkt (pkt);
 
} // rsp_read_mem ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP write memory (symbolic) request
 
//! Syntax is:
 
//! m<addr>,<length>:<data>
 
//! The data is the bytes, lowest address first, encoded as pairs of hex
//! digits.
 
//! The length given is the number of bytes to be written.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspWriteMem ()
{
uint32_t addr; // Where to write the memory
int len; // Number of bytes to write
 
if (2 != sscanf (pkt->data, "M%x,%x:", &addr, &len))
{
cerr << "Warning: Failed to recognize RSP write memory "
<< pkt->data << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// Find the start of the data and check there is the amount we expect.
char *symDat = (char *)(memchr (pkt->data, ':', pkt->getBufSize())) + 1;
int datLen = pkt->getLen() - (symDat - pkt->data);
 
// Sanity check
if (len * 2 != datLen)
{
cerr << "Warning: Write of " << len * 2 << "digits requested, but "
<< datLen << " digits supplied: packet ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// Write the bytes to memory (no check the address is OK here)
for (int off = 0; off < len; off++)
{
uint8_t nyb1 = Utils::char2Hex (symDat[off * 2]);
uint8_t nyb2 = Utils::char2Hex (symDat[off * 2 + 1]);
 
if (!debugUnit->writeMem8 (addr + off, (nyb1 << 4) | nyb2))
{
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
}
 
pkt->packStr ("OK");
rsp->putPkt (pkt);
 
} // rspWriteMem ()
 
 
//-----------------------------------------------------------------------------
//! Read a single register
 
//! 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
//! sequence of bytes in target endian order.
 
//! Each byte is packed as a pair of hex digits.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspReadReg ()
{
unsigned int regNum;
 
// Break out the fields from the data
if (1 != sscanf (pkt->data, "p%x", &regNum))
{
cerr << "Warning: Failed to recognize RSP read register command: "
<< pkt->data << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// Get the relevant register
if (regNum < max_gprs)
{
Utils::Utils::reg2Hex (readGpr (regNum), pkt->data);
}
else if (PPC_REGNUM == regNum)
{
Utils::Utils::reg2Hex (debugUnit->readSpr (SPR_PPC), pkt->data);
}
else if (NPC_REGNUM == regNum)
{
Utils::Utils::reg2Hex (readNpc (), pkt->data);
}
else if (SR_REGNUM == regNum)
{
Utils::Utils::reg2Hex (debugUnit->readSpr (SPR_SR), pkt->data);
}
else
{
// Error response if we don't know the register
cerr << "Warning: Attempt to read unknown register" << regNum
<< ": ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
pkt->setLen (strlen (pkt->data));
rsp->putPkt (pkt);
 
} // rspWriteReg ()
 
//-----------------------------------------------------------------------------
//! Write a single register
 
//! 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
//! sequence of bytes in target endian order.
 
//! Each byte is packed as a pair of hex digits.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspWriteReg ()
{
unsigned int regNum;
char valstr[9]; // Allow for EOS on the string
 
// Break out the fields from the data
if (2 != sscanf (pkt->data, "P%x=%8s", &regNum, valstr))
{
cerr << "Warning: Failed to recognize RSP write register command "
<< pkt->data << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
// Set the relevant register
if (regNum < max_gprs)
{
writeGpr (regNum, Utils::hex2Reg (valstr));
}
else if (PPC_REGNUM == regNum)
{
debugUnit->writeSpr (SPR_PPC, Utils::hex2Reg (valstr));
}
else if (NPC_REGNUM == regNum)
{
writeNpc (Utils::hex2Reg (valstr));
}
else if (SR_REGNUM == regNum)
{
debugUnit->writeSpr (SPR_SR, Utils::hex2Reg (valstr));
}
else
{
// Error response if we don't know the register
cerr << "Warning: Attempt to write unknown register " << regNum
<< ": ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
pkt->packStr ("OK");
rsp->putPkt (pkt);
 
} // rspWriteReg ()
 
//-----------------------------------------------------------------------------
//! Handle a RSP query request
//-----------------------------------------------------------------------------
void
GdbServerSC::rspQuery ()
{
if (0 == strcmp ("qC", pkt->data))
{
// Return the current thread ID (unsigned hex). A null response
// indicates to use the previously selected thread. We use the constant
// OR1KSIM_TID to represent our single thread of control.
sprintf (pkt->data, "QC%x", OR1KSIM_TID);
pkt->setLen (strlen (pkt->data));
rsp->putPkt (pkt);
}
else if (0 == strncmp ("qCRC", pkt->data, strlen ("qCRC")))
{
// Return CRC of memory area
cerr << "Warning: RSP CRC query not supported" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
}
else if (0 == strcmp ("qfThreadInfo", pkt->data))
{
// Return info about active threads. We return just the constant
// OR1KSIM_TID to represent our single thread of control.
sprintf (pkt->data, "m%x", OR1KSIM_TID);
pkt->setLen (strlen (pkt->data));
rsp->putPkt (pkt);
}
else if (0 == strcmp ("qsThreadInfo", pkt->data))
{
// Return info about more active threads. We have no more, so return the
// end of list marker, 'l'
pkt->packStr ("l");
rsp->putPkt (pkt);
}
else if (0 == strncmp ("qGetTLSAddr:", pkt->data, strlen ("qGetTLSAddr:")))
{
// We don't support this feature
pkt->packStr ("");
rsp->putPkt (pkt);
}
else if (0 == strncmp ("qL", pkt->data, strlen ("qL")))
{
// Deprecated and replaced by 'qfThreadInfo'
cerr << "Warning: RSP qL deprecated: no info returned" << endl;
pkt->packStr ("qM001");
rsp->putPkt (pkt);
}
else if (0 == strcmp ("qOffsets", pkt->data))
{
// Report any relocation
pkt->packStr ("Text=0;Data=0;Bss=0");
rsp->putPkt (pkt);
}
else if (0 == strncmp ("qP", pkt->data, strlen ("qP")))
{
// Deprecated and replaced by 'qThreadExtraInfo'
cerr << "Warning: RSP qP deprecated: no info returned" << endl;
pkt->packStr ("");
rsp->putPkt (pkt);
}
else if (0 == strncmp ("qRcmd,", pkt->data, strlen ("qRcmd,")))
{
// This is used to interface to commands to do "stuff"
rspCommand ();
}
else if (0 == strncmp ("qSupported", pkt->data, strlen ("qSupported")))
{
// 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
// 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
// EOS so the buffer is a well formed string.
sprintf (pkt->data, "PacketSize=%x", pkt->getBufSize());
pkt->setLen (strlen (pkt->data));
rsp->putPkt (pkt);
}
else if (0 == strncmp ("qSymbol:", pkt->data, strlen ("qSymbol:")))
{
// 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
// do that anyway!
pkt->packStr ("OK");
rsp->putPkt (pkt);
}
else if (0 == strncmp ("qThreadExtraInfo,", pkt->data,
strlen ("qThreadExtraInfo,")))
{
// Report that we are runnable, but the text must be hex ASCI
// digits. For now do this by steam, reusing the original packet
sprintf (pkt->data, "%02x%02x%02x%02x%02x%02x%02x%02x%02x",
'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0);
pkt->setLen (strlen (pkt->data));
rsp->putPkt (pkt);
}
else if (0 == strncmp ("qXfer:", pkt->data, strlen ("qXfer:")))
{
// For now we support no 'qXfer' requests, but these should not be
// expected, since they were not reported by 'qSupported'
cerr << "Warning: RSP 'qXfer' not supported: ignored" << endl;
pkt->packStr ("");
rsp->putPkt (pkt);
}
else
{
cerr << "Unrecognized RSP query: ignored" << endl;
}
} // rspQuery ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP qRcmd request
 
//! The actual command follows the "qRcmd," in ASCII encoded to hex
//-----------------------------------------------------------------------------
void
GdbServerSC::rspCommand ()
{
char cmd[RSP_PKT_MAX];
 
Utils::hex2Ascii (cmd, &(pkt->data[strlen ("qRcmd,")]));
 
// Work out which command it is
if (0 == strncmp ("readspr ", cmd, strlen ("readspr")))
{
unsigned int sprNum;
 
// Parse and return error if we fail
if( 1 != sscanf (cmd, "readspr %4x", &sprNum))
{
cerr << "Warning: qRcmd " << cmd
<< "not recognized: ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// SPR out of range
if (sprNum > MAX_SPRS)
{
cerr << "Warning: qRcmd readspr " << hex << sprNum
<< dec << " too large: ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// Construct the reply
sprintf (cmd, "%8lx", debugUnit->readSpr (sprNum));
Utils::ascii2Hex (pkt->data, cmd);
pkt->setLen (strlen (pkt->data));
rsp->putPkt (pkt);
}
else if (0 == strncmp ("writespr ", cmd, strlen ("writespr")))
{
unsigned int sprNum;
uint32_t val;
 
// Parse and return error if we fail
if( 2 != sscanf (cmd, "writespr %4x %8lx", &sprNum, &val))
{
cerr << "Warning: qRcmd " << cmd << " not recognized: ignored"
<< endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// SPR out of range
if (sprNum > MAX_SPRS)
{
cerr << "Warning: qRcmd writespr " << hex << sprNum
<< dec << " too large: ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// Update the SPR and reply "OK"
debugUnit->writeSpr (sprNum, val);
pkt->packStr ("OK");
rsp->putPkt (pkt);
}
} // rspCommand ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP set request
//-----------------------------------------------------------------------------
void
GdbServerSC::rspSet ()
{
if (0 == strncmp ("QPassSignals:", pkt->data, strlen ("QPassSignals:")))
{
// Passing signals not supported
pkt->packStr ("");
rsp->putPkt (pkt);
}
else if ((0 == strncmp ("QTDP", pkt->data, strlen ("QTDP"))) ||
(0 == strncmp ("QFrame", pkt->data, strlen ("QFrame"))) ||
(0 == strcmp ("QTStart", pkt->data)) ||
(0 == strcmp ("QTStop", pkt->data)) ||
(0 == strcmp ("QTinit", pkt->data)) ||
(0 == strncmp ("QTro", pkt->data, strlen ("QTro"))))
{
// All tracepoint features are not supported. This reply is really only
// needed to 'QTDP', since with that the others should not be
// generated.
pkt->packStr ("");
rsp->putPkt (pkt);
}
else
{
cerr << "Unrecognized RSP set request: ignored" << endl;
delete pkt;
}
} // rspSet ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP restart request
 
//! 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
//! there. There is no point in unstalling the processor, since we'll never
//! get control back.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspRestart ()
{
writeNpc (EXCEPT_RESET);
 
} // rspRestart ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP step request
 
//! 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.
 
//! @param[in] except The exception to use. Only EXCEPT_NONE should be set
//! this way.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspStep (uint32_t except)
{
uint32_t addr; // The address to step from, if any
// Reject all except 's' packets
if ('s' != pkt->data[0])
{
cerr << "Warning: Step with signal not currently supported: "
<< "ignored" << endl;
return;
}
 
if (0 == strcmp ("s", pkt->data))
{
addr = readNpc (); // Default uses current NPC
}
else if (1 != sscanf (pkt->data, "s%lx", &addr))
{
cerr << "Warning: RSP step address " << pkt->data
<< " not recognized: ignored" << endl;
addr = readNpc (); // Default uses current NPC
}
 
rspStep (addr, EXCEPT_NONE);
 
} // rspStep ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP step with signal request
 
//! @todo Currently null. Will use the underlying generic step function.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspStep ()
{
cerr << "RSP step with signal '" << pkt->data << "' received" << endl;
 
} // rspStep ()
 
 
//-----------------------------------------------------------------------------
//! Generic processing of a step request
 
//! The signal may be EXCEPT_NONE if there is no exception to be
//! handled. Currently the exception is ignored.
 
//! The single step flag is set in the debug registers and then the processor
//! is unstalled.
 
//! @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
//! executions of the same instruction. A fix would be to use l.trap (as
//! for continue) for any consecutive calls to step.
 
//! @param[in] addr Address from which to step
//! @param[in] except The exception to use (if any)
//-----------------------------------------------------------------------------
void
GdbServerSC::rspStep (uint32_t addr,
uint32_t except)
{
// Set the address as the value of the next program counter
writeNpc (addr);
/*
// If we're continuing from a breakpoint, replace that instruction in the memory
// ... actually no, I was wrong about this.
if (NULL != mpHash->lookup (BP_MEMORY, addr) && rsp_sigval == TARGET_SIGNAL_TRAP)
{
MpEntry *entry = mpHash->lookup (BP_MEMORY, addr);
debugUnit->writeMem32(entry->addr, entry->instr);
}
*/
// Clear Debug Reason Register and watchpoint break generation in Debug Mode
// Register 2 for watchpoints that we triggered to stop this time.
debugUnit->writeSpr (SPR_DRR, 0);
if (rsp_sigval == TARGET_SIGNAL_TRAP)
{
/*
Disable last trap generation on watchpoint if this is why we stopped
last time.
*/
uint32_t temp_dmr2 = debugUnit->readSpr (SPR_DMR2);
if (temp_dmr2 & SPR_DMR2_WBS)
{
/*
One of these breakpoints is responsible for our stopping, so
disable it this time we start. GDB will send a packet re-enabling
it next time we continue.
*/
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
// handled by the debug unit in the Debug Stop Register
debugUnit->orSpr (SPR_DMR1, SPR_DMR1_ST);
debugUnit->orSpr (SPR_DSR, SPR_DSR_TE);
 
// Unstall the processor. Note the GDB client is now waiting for a reply,
// which it will get as soon as the processor stalls again.
debugUnit->unstall ();
targetStopped = false;
 
} // rspStep ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP 'v' packet
 
//! These are commands associated with executing the code on the target
//-----------------------------------------------------------------------------
void
GdbServerSC::rspVpkt ()
{
if (0 == strncmp ("vAttach;", pkt->data, strlen ("vAttach;")))
{
// Attaching is a null action, since we have no other process. We just
// return a stop packet (using TRAP) to indicate we are stopped.
pkt->packStr ("S05");
rsp->putPkt (pkt);
return;
}
else if (0 == strcmp ("vCont?", pkt->data))
{
// For now we don't support this.
pkt->packStr ("");
rsp->putPkt (pkt);
return;
}
else if (0 == strncmp ("vCont", pkt->data, strlen ("vCont")))
{
// This shouldn't happen, because we've reported non-support via vCont?
// above
cerr << "Warning: RSP vCont not supported: ignored" << endl;
return;
}
else if (0 == strncmp ("vFile:", pkt->data, strlen ("vFile:")))
{
// For now we don't support this.
cerr << "Warning: RSP vFile not supported: ignored" << endl;
pkt->packStr ("");
rsp->putPkt (pkt);
return;
}
else if (0 == strncmp ("vFlashErase:", pkt->data, strlen ("vFlashErase:")))
{
// For now we don't support this.
cerr << "Warning: RSP vFlashErase not supported: ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
else if (0 == strncmp ("vFlashWrite:", pkt->data, strlen ("vFlashWrite:")))
{
// For now we don't support this.
cerr << "Warning: RSP vFlashWrite not supported: ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
else if (0 == strcmp ("vFlashDone", pkt->data))
{
// For now we don't support this.
cerr << "Warning: RSP vFlashDone not supported: ignored" << endl;;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
else if (0 == strncmp ("vRun;", pkt->data, strlen ("vRun;")))
{
// We shouldn't be given any args, but check for this
if (pkt->getLen () > strlen ("vRun;"))
{
cerr << "Warning: Unexpected arguments to RSP vRun "
"command: ignored" << endl;
}
 
// Restart the current program. However unlike a "R" packet, "vRun"
// should behave as though it has just stopped. We use signal 5 (TRAP).
rspRestart ();
pkt->packStr ("S05");
rsp->putPkt (pkt);
}
else
{
cerr << "Warning: Unknown RSP 'v' packet type " << pkt->data
<< ": ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
} // rspVpkt ()
 
 
//-----------------------------------------------------------------------------
//! Handle a RSP write memory (binary) request
 
//! Syntax is:
 
//! X<addr>,<length>:
 
//! 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.
 
//! 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.
 
//! The data is in model-endian format, so no transformation is needed.
//-----------------------------------------------------------------------------
void
GdbServerSC::rspWriteMemBin ()
{
uint32_t addr; // Where to write the memory
int len; // Number of bytes to write
 
if (2 != sscanf (pkt->data, "X%x,%x:", &addr, &len))
{
cerr << "Warning: Failed to recognize RSP write memory command: %s"
<< pkt->data << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// 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
// below!
uint8_t *bindat = (uint8_t *)(memchr (pkt->data, ':',
pkt->getBufSize ())) + 1;
int off = (char *)bindat - pkt->data;
int newLen = Utils::rspUnescape ((char *)bindat, pkt->getLen () - off);
 
// Sanity check
if (newLen != len)
{
int minLen = len < newLen ? len : newLen;
 
cerr << "Warning: Write of " << len << " bytes requested, but "
<< newLen << " bytes supplied. " << minLen << " will be written"
<< endl;
len = minLen;
}
 
// Write the bytes to memory. More efficent to do this in 32-bit chunks
int startBytes = addr & 0x3;
int endBytes = (addr + len) & 0x3;
 
// First partial word. Access bindat in an endian independent fashion.
for (off = 0 ; off < startBytes ; off++)
{
if (!debugUnit->writeMem8 (addr + off, bindat[off]))
{
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
}
 
// The bulk as words. Convert to model endian before writing.
for (off = startBytes; off < len; off += 4)
{
uint32_t val = *((uint32_t *)(&(bindat[off])));
 
if (!debugUnit->writeMem32 (addr + off, Utils::htotl (val)))
{
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
}
 
// Last partial word. Access bindat in an endian independent fashion.
for (off = len - endBytes; off < len ; off++)
{
uint32_t base = (addr + len) & 0xfffffffc;
 
if (!debugUnit->writeMem8 (base + off, bindat[off]))
{
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
}
 
pkt->packStr ("OK");
rsp->putPkt (pkt);
 
} // rspWriteMemBin ()
 
//-----------------------------------------------------------------------------
//! Handle a RSP remove breakpoint or matchpoint request
 
//! For now only memory breakpoints are implemented, which are implemented by
//! substituting a breakpoint at the specified address. The implementation must
//! cope with the possibility of duplicate packets.
 
//! @todo This doesn't work with icache/immu yet
//-----------------------------------------------------------------------------
void
GdbServerSC::rspRemoveMatchpoint ()
{
MpType type; // What sort of matchpoint
uint32_t addr; // Address specified
uint32_t instr; // Instruction value found
int len; // Matchpoint length (not used)
 
// Break out the instruction
if (3 != sscanf (pkt->data, "z%1d,%lx,%1d", (int *)&type, &addr, &len))
{
cerr << "Warning: RSP matchpoint deletion request not "
<< "recognized: ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// Sanity check that the length is 4
if (4 != len)
{
cerr << "Warning: RSP matchpoint deletion length " << len
<< "not valid: 4 assumed" << endl;
len = 4;
}
// Sort out the type of matchpoint
switch (type)
{
case BP_MEMORY:
// Memory breakpoint - replace the original instruction.
if (mpHash->remove (type, addr, &instr))
{
//cerr << "rspRemoveMatchpoint at 0x" << hex << addr << " restoring instruction: 0x" << hex << instr <<endl;
debugUnit->writeMem32 (addr, instr);
}
 
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
case BP_HARDWARE:
int off;
for (off=0;off<8;off++)
if ((debugUnit->readSpr (SPR_DCR0+off) == (0x23)) &&
(debugUnit->readSpr (SPR_DVR0+off) == addr))
break;
if (off > 7)
{
pkt->packStr ("E02"); // Failed ot find breakpoint
rsp->putPkt (pkt);
return;
}
// Clear DCR's CT and DVR, WGB bit
debugUnit->writeSpr (SPR_DCR0+off,0);
debugUnit->writeSpr (SPR_DVR0+off,0);
debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2) & ~((1<<off)<<SPR_DMR2_WGB_SHIFT));
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
 
case WP_WRITE:
{
int off;
for (off=0;off<8;off++)
{
if ((debugUnit->readSpr (SPR_DCR0+off) == (0x63)) &&
(debugUnit->readSpr (SPR_DVR0+off) == addr))
break;
}
if (off > 7)
{
pkt->packStr ("E02"); // Failed ot find breakpoint
rsp->putPkt (pkt);
return;
}
 
// Clear DCR's CT and DVR, WGB bit
debugUnit->writeSpr (SPR_DCR0+off,0);
debugUnit->writeSpr (SPR_DVR0+off,0);
debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2) & ~((1<<off)<<SPR_DMR2_WGB_SHIFT));
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
}
case WP_READ:
{
int off;
for (off=0;off<8;off++)
{
if ((debugUnit->readSpr (SPR_DCR0+off) == (0x43)) &&
(debugUnit->readSpr (SPR_DVR0+off) == addr))
break;
}
if (off > 7)
{
pkt->packStr ("E02"); // Failed ot find breakpoint
rsp->putPkt (pkt);
return;
}
 
// Clear DCR's CT and DVR, WGB bit
debugUnit->writeSpr (SPR_DCR0+off,0);
debugUnit->writeSpr (SPR_DVR0+off,0);
debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2) & ~((1<<off)<<SPR_DMR2_WGB_SHIFT));
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
}
case WP_ACCESS:
{
int off;
for (off=0;off<8;off++)
{
//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));
if ((debugUnit->readSpr (SPR_DCR0+off) == (0xc3)) &&
(debugUnit->readSpr (SPR_DVR0+off) == addr))
break;
}
if (off > 7)
{
//printf("rspRemoveWatchpoint: WP_ACCESS remove ERROR, regpair %d for 0x%.8x\n",off, addr);
pkt->packStr ("E02"); // Failed ot find breakpoint
rsp->putPkt (pkt);
return;
}
//printf("rspRemoveWatchpoint: WP_ACCESS remove, regpair %d for 0x%.8x\n",off, addr);
 
// Clear DCR's CT and DVR, WGB bit
debugUnit->writeSpr (SPR_DCR0+off,0);
debugUnit->writeSpr (SPR_DVR0+off,0);
debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2) & ~((1<<off)<<SPR_DMR2_WGB_SHIFT));
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
}
default:
cerr << "Warning: RSP matchpoint type " << type
<< " not recognized: ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
} // rspRemoveMatchpoint ()
 
//---------------------------------------------------------------------------*/
//! Handle a RSP insert breakpoint or matchpoint request
 
//! For now only memory breakpoints are implemented, which are implemented by
//! substituting a breakpoint at the specified address. The implementation must
//! cope with the possibility of duplicate packets.
 
//! @todo This doesn't work with icache/immu yet
//---------------------------------------------------------------------------*/
void
GdbServerSC::rspInsertMatchpoint ()
{
MpType type; // What sort of matchpoint
uint32_t addr; // Address specified
int len; // Matchpoint length (not used)
// Break out the instruction
if (3 != sscanf (pkt->data, "Z%1d,%lx,%1d", (int *)&type, &addr, &len))
{
cerr << "Warning: RSP matchpoint insertion request not "
<< "recognized: ignored" << endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
 
// Sanity check that the length is 4
if (4 != len)
{
cerr << "Warning: RSP matchpoint insertion length " << len
<< "not valid: 4 assumed" << endl;
len = 4;
}
 
// Sort out the type of matchpoint
switch (type)
{
case BP_MEMORY:
// Memory breakpoint - substitute a TRAP instruction
mpHash->add (type, addr, debugUnit->readMem32 (addr));
debugUnit->writeMem32 (addr, OR1K_TRAP_INSTR);
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
case BP_HARDWARE:
{
int off;
for (off=0;off<8;off++)
if (!(debugUnit->readSpr (SPR_DCR0+off) & SPR_DCR_CT_MASK))
break;
if (off > 7)
{
pkt->packStr (""); // No room
rsp->putPkt (pkt);
return;
}
// CC = equal, CT = Instruction fetch EA, set WGB bit
debugUnit->writeSpr (SPR_DCR0+off,0x22);
debugUnit->writeSpr (SPR_DVR0+off,addr);
debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2)|((1<<off)<<SPR_DMR2_WGB_SHIFT));
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
}
 
case WP_WRITE:
{
int off;
for (off=0;off<8;off++)
if (!(debugUnit->readSpr (SPR_DCR0+off) & SPR_DCR_CT_MASK))
break;
//printf("rspInsertWatchpoint: WP_WRITE, regpair %d for 0x%.8x\n",off, addr);
if (off > 7)
{
pkt->packStr (""); // No room
rsp->putPkt (pkt);
return;
}
// CC = equal, CT = Store EA, set WGB bit
debugUnit->writeSpr (SPR_DCR0+off,0x62);
debugUnit->writeSpr (SPR_DVR0+off,addr);
debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2)|((1<<off)<<SPR_DMR2_WGB_SHIFT));
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
}
 
case WP_READ:
{
int off;
for (off=0;off<8;off++)
if (!(debugUnit->readSpr (SPR_DCR0+off) & SPR_DCR_CT_MASK))
break;
//printf("rspInsertWatchpoint: WP_WRITE, regpair %d for 0x%.8x\n",off, addr);
if (off > 7)
{
pkt->packStr (""); // No room
rsp->putPkt (pkt);
return;
}
// CC = equal, CT = Load EA, set WGB bit
debugUnit->writeSpr (SPR_DCR0+off,0x42);
debugUnit->writeSpr (SPR_DVR0+off,addr);
debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2)|((1<<off)<<SPR_DMR2_WGB_SHIFT));
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
}
 
pkt->packStr (""); // Not supported
rsp->putPkt (pkt);
return;
 
case WP_ACCESS:
{
int off;
for (off=0;off<8;off++)
if (!(debugUnit->readSpr (SPR_DCR0+off) & SPR_DCR_CT_MASK))
break;
//printf("rspInsertWatchpoint: WP_ACCESS, regpair %d for 0x%.8x\n",off, addr);
if (off > 7)
{
pkt->packStr (""); // No room
rsp->putPkt (pkt);
return;
}
// CC = equal, CT = Load/Store EA, set WGB bit
debugUnit->writeSpr (SPR_DCR0+off,0xc2);
debugUnit->writeSpr (SPR_DVR0+off,addr);
debugUnit->writeSpr (SPR_DMR2,debugUnit->readSpr (SPR_DMR2)|((1<<off)<<SPR_DMR2_WGB_SHIFT));
pkt->packStr ("OK");
rsp->putPkt (pkt);
return;
}
 
default:
cerr << "Warning: RSP matchpoint type " << type
<< "not recognized: ignored"<< endl;
pkt->packStr ("E01");
rsp->putPkt (pkt);
return;
}
} // rspInsertMatchpoint ()
 
 
//-----------------------------------------------------------------------------
//! Read the value of the Next Program Counter (a SPR)
 
//! A convenience routine.
 
//! Setting the NPC flushes the pipeline, so subsequent reads will return
//! 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).
 
//! 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
//! refilled). Fortunately SPR cacheing in the debug unit silently solves this
//! for us.
 
//! @return The value of the NPC
//-----------------------------------------------------------------------------
uint32_t
GdbServerSC::readNpc ()
{
return debugUnit->readSpr (SPR_NPC);
 
} // readNpc ()
 
 
//-----------------------------------------------------------------------------
//! Write the value of the Next Program Counter (a SPR)
 
//! A convenience function.
 
//! Setting the NPC flushes the pipeline, so subsequent reads will return
//! 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).
 
//! 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
//! refilled). Fortunately SPR cacheing in the debug unit silently solves this
//! for us.
 
//! 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
//! always read it first before writing.
 
//! @param[in] The address to write into the NPC
//-----------------------------------------------------------------------------
void
GdbServerSC::writeNpc (uint32_t addr)
{
if (addr != readNpc())
{
debugUnit->writeSpr (SPR_NPC, addr);
}
} // writeNpc ()
 
 
//-----------------------------------------------------------------------------
//! Read the value of an OpenRISC 1000 General Purpose Register
 
//! A convenience function. This is just a wrapper for reading a SPR, since
//! the GPR's are mapped into SPR space
 
//! @param[in] regNum The GPR to read
 
//! @return The value of the GPR
//-----------------------------------------------------------------------------
uint32_t
GdbServerSC::readGpr (int regNum)
{
return debugUnit->readSpr (SPR_GPR0 + regNum);
 
} // readGpr ()
 
 
//-----------------------------------------------------------------------------
//! Write the value of an OpenRISC 1000 General Purpose Register
 
//! A convenience function. This is just a wrapper for writing a SPR, since
//! the GPR's are mapped into SPR space
 
//! @param[in] regNum The GPR to read
 
//! @return The value of the GPR
//-----------------------------------------------------------------------------
void
GdbServerSC::writeGpr (int regNum,
uint32_t value)
{
debugUnit->writeSpr (SPR_GPR0 + regNum, value);
 
} // writeGpr ()
 
//-----------------------------------------------------------------------------
//! 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
//! had been received. Perhaps the sigval should be set differently/more
//! more appropriately.
//! Read from the pipe should be NON-blocking.
 
//! @return false if nothing received, else true
//-----------------------------------------------------------------------------
bool
GdbServerSC::checkMonitorPipe ()
{
char readChar;
int n = read(monitor_to_gdb_pipe[0][0], &readChar, sizeof(char));
if (!( ((n < 0) && (errno == EAGAIN)) || (n==0) ) && !targetStopped)
{
debugUnit->stall ();
// Send a stop reply response, manually set rsp.sigval to TARGET_SIGNAL_NONE
rsp_sigval = TARGET_SIGNAL_NONE;
rspReportException();
targetStopped = true; // Processor now not running
write(monitor_to_gdb_pipe[1][1],&readChar,sizeof(char));
return true;
}
return false;
} // checkMonitorPipe ()
/src/TapStateMachine.cpp
0,0 → 1,180
// ----------------------------------------------------------------------------
 
// The TAP state machine: implementation
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
#include "TapStateMachine.h"
 
//! Constructor
 
//! Start in the Test-Logic-Reset state, although we cannot know this reflects
//! the hardware until it has been through a TAP reset sequence. This is
//! reflected in the ::tapResetDone flag.
 
TapStateMachine::TapStateMachine () :
state (TAP_TEST_LOGIC_RESET),
resetDone (false)
{
 
} // TapStateMachine ()
 
 
//! Accessor to get the current TAP state
 
//! Only guaranteed to match the target hardware if it has been through a
//! reset sequence.
 
//! @return The current TAP state
TapState
TapStateMachine::getState ()
{
return state;
 
} // getState ()
 
 
//! Accessor to get the current TAP reset state.
 
//! It is the responsibility of classes using this class to correctly set this
//! state.
 
//! @return The current TAP reset state
bool
TapStateMachine::getResetDone ()
{
return resetDone;
 
} // getResetDone ()
 
 
//! Accessor to set the current TAP reset state.
 
//! It is the responsibility of classes using this class to correctly set this
//! state.
 
//! @param[in] The desired TAP reset state
void
TapStateMachine::setResetDone (bool _resetDone)
{
resetDone = _resetDone;
 
} // setResetDone ()
 
 
//! Drive the TAP state machine
 
//! @param tms The JTAG TMS pin
void
TapStateMachine::nextState (bool tms)
{
static const TapState mapHigh[TAP_SIZE] = { // When TMS = 1/true
TAP_TEST_LOGIC_RESET, // from TAP_TEST_LOGIC_RESET
TAP_SELECT_DR_SCAN, // from TAP_RUN_TEST_IDLE
TAP_SELECT_IR_SCAN, // from TAP_SELECT_DR_SCAN
TAP_EXIT1_DR, // from TAP_CAPTURE_DR
TAP_EXIT1_DR, // from TAP_SHIFT_DR
TAP_UPDATE_DR, // from TAP_EXIT1_DR
TAP_EXIT2_DR, // from TAP_PAUSE_DR
TAP_UPDATE_DR, // from TAP_EXIT2_DR
TAP_SELECT_DR_SCAN, // from TAP_UPDATE_DR
TAP_TEST_LOGIC_RESET, // from TAP_SELECT_IR_SCAN
TAP_EXIT1_IR, // from TAP_CAPTURE_IR
TAP_EXIT1_IR, // from TAP_SHIFT_IR
TAP_UPDATE_IR, // from TAP_EXIT1_IR
TAP_EXIT2_IR, // from TAP_PAUSE_IR
TAP_UPDATE_IR, // from TAP_EXIT2_IR
TAP_SELECT_DR_SCAN}; // from TAP_UPDATE_IR
 
static const TapState mapLow[TAP_SIZE] = { // When TMS = 0/false
TAP_RUN_TEST_IDLE, // from TAP_TEST_LOGIC_RESET
TAP_RUN_TEST_IDLE, // from TAP_RUN_TEST_IDLE
TAP_CAPTURE_DR, // from TAP_SELECT_DR_SCAN
TAP_SHIFT_DR, // from TAP_CAPTURE_DR
TAP_SHIFT_DR, // from TAP_SHIFT_DR
TAP_PAUSE_DR, // from TAP_EXIT1_DR
TAP_PAUSE_DR, // from TAP_PAUSE_DR
TAP_SHIFT_DR, // from TAP_EXIT2_DR
TAP_RUN_TEST_IDLE, // from TAP_UPDATE_DR
TAP_CAPTURE_IR, // from TAP_SELECT_IR_SCAN
TAP_SHIFT_IR, // from TAP_CAPTURE_IR
TAP_SHIFT_IR, // from TAP_SHIFT_IR
TAP_PAUSE_IR, // from TAP_EXIT1_IR
TAP_PAUSE_IR, // from TAP_PAUSE_IR
TAP_SHIFT_IR, // from TAP_EXIT2_IR
TAP_RUN_TEST_IDLE }; // from TAP_UPDATE_IR
 
state = tms ? mapHigh[state] : mapLow[state];
 
} // nextState()
 
 
//! Determine if we are in a particular TAP state
 
//! Set TMS to get there optimally
 
//! @param[in] target The desired TAP state
//! @param[out] tms Value of TMS to move towards the target state. Set
//! even if we are already in the state (in case we want
//! to loop).
 
//! @return True if we are already in the target state
bool
TapStateMachine::targetState (TapState target,
bool &tms)
{
// Map of the value of TMS which moves the state machine from the the state
// in the row (first) to the state in the column (second)
static const bool map[TAP_SIZE][TAP_SIZE] = {
// T R S C S E P E U S C S E P E U
// L T D D D 1 D 2 D I I I 1 I 2 I
// R I R R R D R D R R R R I R I R
// S R R S R R
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // map[TLR][x]
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // map[RTI][x]
{ 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }, // map[SDRS][x]
{ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // map[CDR][x]
{ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // map[SDR][x]
{ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, // map[E1DR][x]
{ 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // map[PDR][x]
{ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, // map[E2DR][x]
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // map[UDR][x]
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 }, // map[SIRS][x]
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }, // map[CIR][x]
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }, // map[SIR][x]
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1 }, // map[E1IR][x]
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, // map[PIR][x]
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1 }, // map[E2IR][x]
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }}; // map[UIR][x]
 
tms = map[state][target];
return state == target;
 
} // targetState()
/src/OrpsocMain.cpp
1,4 → 1,4
//////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//// ////
//// ORPSoC SystemC Testbench ////
//// ////
6,7 → 6,6
//// ORPSoC Testbench file ////
//// ////
//// To Do: ////
//// Somehow allow tracing to begin later in the sim ////
//// ////
//// ////
//// Author(s): ////
43,6 → 42,8
 
#include "OrpsocMain.h"
 
#include "jtagsc.h"
 
#include "Vorpsoc_top.h"
#include "OrpsocAccess.h"
#include "MemoryLoad.h"
49,9 → 50,9
 
#include <SpTraceVcdC.h>
 
//#include "TraceSC.h"
#include "ResetSC.h"
#include "Or1200MonitorSC.h"
#include "GdbServerSC.h"
#include "UartSC.h"
 
int SIM_RUNNING;
61,8 → 62,11
sc_set_time_resolution( 1, TIMESCALE_UNIT);
// CPU clock (also used as JTAG TCK) and reset (both active high and low)
sc_time clkPeriod (BENCH_CLK_HALFPERIOD * 2.0, TIMESCALE_UNIT);
sc_time jtagPeriod (JTAG_CLK_HALFPERIOD * 2.0, TIMESCALE_UNIT);
 
sc_clock clk ("clk", clkPeriod);
sc_clock jtag_tck ("jtag-clk", jtagPeriod, 0.5, SC_ZERO_TIME, false);
sc_signal<bool> rst;
sc_signal<bool> rstn;
sc_signal<bool> rst_o;
90,21 → 94,24
SIM_RUNNING = 0;
 
// Setup the name of the VCD dump file
int VCD_enabled = 0;
bool VCD_enabled = false;
string dumpNameDefault("vlt-dump.vcd");
string testNameString;
string vcdDumpFile;
// VCD dump controling vars
int dump_start_delay, dump_stop_set;
int dumping_now;
bool dump_start_delay_set = false, dump_stop_set = false;
bool dumping_now = false;
int dump_depth = 99; // Default dump depth
sc_time dump_start,dump_stop, finish_time;
int finish_time_set = 0; // By default we will let the simulation finish naturally
bool finish_time_set = false; // By default we will let the simulation finish naturally
SpTraceVcdCFile *spTraceFile;
int time_val;
int cmdline_name_found=0;
/*int*/double time_val;
bool vcd_file_name_given = false;
 
bool rsp_server_enabled = false;
int rsp_server_port = DEFAULT_RSP_PORT;
 
// Executable app load variables
int do_program_file_load = 0; // Default: we don't require a file, we use the VMEM
char* program_file; // Old char* style for program name
119,6 → 126,8
ResetSC *reset; // Generate a RESET signal
Or1200MonitorSC *monitor; // Handle l.nop x instructions
JtagSC *jtag; // Generate JTAG signals
GdbServerSC *gdbServer; // Map RSP requests to debug unit
UartSC *uart; // Handle UART signals
 
// Instantiate the Verilator model, VCD trace handler and accessor
128,16 → 137,18
memoryload = new MemoryLoad (accessor);
monitor = new Or1200MonitorSC ("monitor", accessor, memoryload,
argc, argv);
// Instantiate the SystemC modules
reset = new ResetSC ("reset", BENCH_RESET_TIME);
monitor = new Or1200MonitorSC ("monitor", accessor, memoryload, argc, argv);
jtag = new JtagSC ("jtag");
 
uart = new UartSC("uart"); // TODO: Probalby some sort of param
 
// Parse command line options
// Default is for VCD generation OFF, only turned on if specified on command line
dump_start_delay = 0;
dump_stop_set = 0;
dumping_now = 0;
// Search through the command line parameters for options
if (argc > 1)
144,25 → 155,13
{
for(int i=1; i<argc; i++)
{
if ((strcmp(argv[i], "-d")==0) ||
(strcmp(argv[i], "--vcdfile")==0))
if ( (strcmp(argv[i], "-e")==0) ||
(strcmp(argv[i], "--endtime")==0) )
{
testNameString = (argv[i+1]);
vcdDumpFile = testNameString;
cmdline_name_found=1;
}
else if ((strcmp(argv[i], "-v")==0) ||
(strcmp(argv[i], "--vcdon")==0))
{
dumping_now = 1;
}
else if ( (strcmp(argv[i], "-e")==0) ||
(strcmp(argv[i], "--endtime")==0) )
{
time_val = atoi(argv[i+1]);
time_val = strtod(argv[i+1], NULL);
sc_time opt_end_time(time_val,TIMESCALE_UNIT);
finish_time = opt_end_time;
finish_time_set = 1;
finish_time_set = true;
}
else if ( (strcmp(argv[i], "-f")==0) ||
(strcmp(argv[i], "--program")==0) )
170,26 → 169,56
do_program_file_load = 1; // Enable program loading - will be done after sim init
program_file = argv[i+1]; // Old char* style for program name
}
else if ( (strcmp(argv[i], "-s")==0) ||
else if ((strcmp(argv[i], "-d")==0) ||
(strcmp(argv[i], "--vcdfile")==0) ||
(strcmp(argv[i], "-v")==0) ||
(strcmp(argv[i], "--vcdon")==0)
)
{
VCD_enabled = true;
dumping_now = true;
vcdDumpFile = dumpNameDefault;
if (i+1 < argc)
if(argv[i+1][0] != '-')
{
testNameString = argv[i+1];
vcdDumpFile = testNameString;
i++;
}
}
else if ( (strcmp(argv[i], "-s")==0) ||
(strcmp(argv[i], "--vcdstart")==0) )
{
time_val = atoi(argv[i+1]);
VCD_enabled = true;
time_val = strtod(argv[i+1], NULL);
sc_time dump_start_time(time_val,TIMESCALE_UNIT);
dump_start = dump_start_time;
dump_start_delay = 1;
dumping_now = 0;
dump_start_delay_set = true;
dumping_now = false;
}
else if ( (strcmp(argv[i], "-t")==0) ||
(strcmp(argv[i], "--vcdstop")==0) )
{
time_val = atoi(argv[i+1]);
VCD_enabled = true;
time_val = strtod(argv[i+1],NULL);
sc_time dump_stop_time(time_val,TIMESCALE_UNIT);
dump_stop = dump_stop_time;
dump_stop_set = 1;
dump_stop_set = true;
}
/* Depth setting of VCD doesn't appear to work,
I think it's set during verilator script
compile time */
else if ( (strcmp(argv[i], "-r")==0) ||
(strcmp(argv[i], "--rsp")==0) )
{
rsp_server_enabled = true;
if (i+1 < argc) if(argv[i+1][0] != '-')
{
rsp_server_port = atoi(argv[i+1]);
i++;
}
}
/*
Depth setting of VCD doesn't appear to work, I think it's only
configurable during at compile time .
*/
/* else if ( (strcmp(argv[i], "-p")==0) ||
(strcmp(argv[i], "--vcddepth")==0) )
{
198,18 → 227,23
else if ( (strcmp(argv[i], "-h")==0) ||
(strcmp(argv[i], "--help")==0) )
{
printf("\n ORPSoC Cycle Accurate model usage:\n");
printf(" %s [-vh] [-f <file] [-d <file>] [-e <time>] [-s <time>] [-t <time>]",argv[0]);
monitor->printSwitches();
printf("\n\n");
printf("Usage: %s [options]\n",argv[0]);
printf("\n ORPSoCv2 cycle accurate model\n");
printf(" For details visit http://opencores.org/openrisc,orpsocv2\n");
printf("\n");
printf("Options:\n");
printf(" -h, --help\t\tPrint this help message\n");
printf(" -e, --endtime\t\tStop the sim at this time (ns)\n");
printf(" -f, --program\t\tLoad program from an OR32 ELF\n");
printf("\nSimulation control:\n");
printf(" -f, --program <file> \tLoad program from OR32 ELF <file>\n");
printf(" -e, --endtime <val> \tStop the sim at <val> ns\n");
printf("\nVCD generation:\n");
printf(" -v, --vcdon\t\tEnable VCD generation\n");
printf(" -d, --vcdfile\t\tEnable and specify target VCD file name\n");
printf(" -d, --vcdfile <file>\tEnable and save VCD to <file>\n");
 
printf(" -s, --vcdstart\tEnable and delay VCD generation until this time (ns)\n");
printf(" -t, --vcdstop\t\tEnable and terminate VCD generation at this time (ns)\n");
printf(" -s, --vcdstart <val>\tEnable and delay VCD generation until <val> ns\n");
printf(" -t, --vcdstop <val> \tEnable and terminate VCD generation at <val> ns\n");
printf("\nRemote debugging:\n");
printf(" -r, --rsp [<port>]\tEnable RSP debugging server, opt. specify <port>\n");
monitor->printUsage();
printf("\n");
return 0;
217,32 → 251,33
}
}
 
if(cmdline_name_found==0) // otherwise use our default VCD dump file name
vcdDumpFile = dumpNameDefault;
// Determine if we're going to setup a VCD dump:
// Pretty much setting any option will enable VCD dumping.
if ((cmdline_name_found) || (dumping_now) || (dump_start_delay) || (dump_stop_set))
// Pretty much setting any related option will enable VCD dumping.
if (VCD_enabled)
{
VCD_enabled = 1;
cout << "* Enabling VCD trace";
if (dump_start_delay)
if (dump_start_delay_set)
cout << ", on at time " << dump_start.to_string();
if (dump_stop_set)
cout << ", off at time " << dump_stop.to_string();
cout << ", off at time " << dump_stop.to_string();
cout << endl;
}
 
 
if (rsp_server_enabled)
gdbServer = new GdbServerSC ("gdb-server", FLASH_START, FLASH_END,
rsp_server_port, jtag->tapActionQueue);
else
gdbServer = NULL;
// Connect up ORPSoC
orpsoc->clk_pad_i (clk);
orpsoc->rst_pad_i (rstn);
orpsoc->rst_pad_o (rst_o);
 
orpsoc->dbg_tck_pad_i (clk); // JTAG interface
orpsoc->dbg_tck_pad_i (jtag_tck); // JTAG interface
orpsoc->dbg_tdi_pad_i (jtag_tdi);
orpsoc->dbg_tms_pad_i (jtag_tms);
orpsoc->dbg_tdo_pad_o (jtag_tdo);
264,9 → 299,6
orpsoc->gpio_a_pad_io (gpio_a); // GPIO bus - output only in
// verilator sims
 
// Connect up the VCD trace handler
//trace->clk (clk); // Trace
// Connect up the SystemC modules
reset->clk (clk); // Reset
reset->rst (rst);
274,19 → 306,26
 
monitor->clk (clk); // Monitor
 
jtag->sysReset (rst); // JTAG
jtag->tck (jtag_tck);
jtag->tdi (jtag_tdi);
jtag->tdo (jtag_tdo);
jtag->tms (jtag_tms);
jtag->trst (jtag_trst);
 
uart->clk (clk); // Uart
uart->uartrx (uart_rx); // orpsoc's receive line
uart->uarttx (uart_tx); // orpsoc's transmit line
 
// Tie off signals
jtag_tdi = 1; // Tie off the JTAG inputs
jtag_tms = 1;
// Tie off signals
jtag_tdi = 1; // Tie off the JTAG inputs
jtag_tms = 1;
spi_sd_miso = 0; // Tie off master-in/slave-out of SD SPI bus
 
spi_sd_miso = 0; // Tie off master-in/slave-out of SD SPI bus
 
spi1_miso = 0;
 
//#if VM_TRACE
 
if (VCD_enabled)
{
Verilated::traceEverOn (true);
305,7 → 344,6
{
spTraceFile->open (vcdDumpFile.c_str());
}
//#endif
}
//printf("* Beginning test\n");
345,7 → 383,7
}
else
{
if (dump_start_delay)
if (dump_start_delay_set)
{
// Run the sim until we want to dump
sc_start((double)(dump_start.to_double()),TIMESCALE_UNIT);
424,6 → 462,9
// Free memory
if (rsp_server_enabled)
delete gdbServer;
delete jtag;
delete monitor;
delete reset;
 
/src/JtagSC.cpp
0,0 → 1,117
// ----------------------------------------------------------------------------
 
// Main module providing the JTAG interface: implementation
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
#include "JtagSC.h"
 
 
SC_HAS_PROCESS( JtagSC );
 
//! Constructor for the JTAG handler.
 
//! @param[in] name Name of this module, passed to the parent
//! constructor.
//! @param[in] fifo_size Size of the FIFO on which to queue TAP actions.
 
JtagSC::JtagSC (sc_core::sc_module_name name,
int fifo_size) :
sc_module (name),
currentTapAction (NULL)
{
tapActionQueue = new sc_core::sc_fifo<TapAction *> (fifo_size);
stateMachine = new TapStateMachine ();
 
SC_METHOD (processActions);
sensitive << tck.pos ();
} // JtagSC ()
 
 
//! Destructor for the JTAG handler.
 
//! Give up our state machine and FIFO
 
JtagSC::~JtagSC ()
{
delete stateMachine;
delete tapActionQueue;
 
} // ~JtagSC ()
 
 
//! Method to drive the jtag ports.
 
//! Initial version just drives the reset.
 
void
JtagSC::processActions()
{
// TRST is driven as the inverse of the system reset
trst = !sysReset;
 
// Do nothing else if in CPU reset (active high)
if (sysReset)
{
return;
}
 
// Functions setting the outputs will need bools (they are not generally
// SystemC modules, so don't handle the likes of sc_in<> correctly).
bool tdi_o;
bool tms_o;
 
// Try to get an action if we don't have one
if (NULL == currentTapAction)
{
if (false == tapActionQueue->nb_read (currentTapAction))
{
// Nothing there, so head for Run-Test/Idle state.
stateMachine->targetState (TAP_RUN_TEST_IDLE, tms_o);
tms = tms_o;
 
return;
}
}
// Process the action, notifying the originator when done.
 
if (currentTapAction->process (stateMachine, tdi_o, tdo, tms_o))
{
currentTapAction->getDoneEvent()->notify();
currentTapAction = NULL;
}
 
// Select the new TAP state
stateMachine->nextState (tms_o);
 
// Drive the signal ports
tdi = tdi_o;
tms = tms_o;
 
} // processActions()
/src/DebugUnitSC.cpp
0,0 → 1,1072
// ----------------------------------------------------------------------------
 
// SystemC OpenRISC 1000 Debug Unit: implementation
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
// Copyright (C) 2009 ORSoC
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
// Contributor Julius Baxter <julius@orsoc.se>
 
// 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.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
#include <iostream>
#include <iomanip>
 
#include "DebugUnitSC.h"
#include "Utils.h"
 
 
using sc_core::sc_event;
using sc_core::sc_fifo;
using sc_core::sc_module_name;
 
 
//-----------------------------------------------------------------------------
//! Constructor for the Debug Unit
 
//! This module is entirely subservient to the GDB server. It has no SystemC
//! processes of its own. It provides services via calls to its API.
 
//! The current scan chain is marked as undefined, and the current JTAG scan
//! chain is maked as undefined.
 
//! Caches for SPR and memory access are initialized.
 
//! This makes use of the Embecosm cycle accurate SystemC JTAG interface.
 
//! @see Embecosm Application Note 5 "Using JTAG with SystemC: Implementation
//! of a Cycle Accurate Interface"
//! (http://www.embecosm.com/download/ean5.html)
 
//! @param[in] name Name of this module, passed to the parent
//! constructor.
//! @param[in] _tapActionQueue Pointer to fifo of actions to be performed by
//! the JTAG interface
//-----------------------------------------------------------------------------
DebugUnitSC::DebugUnitSC (sc_module_name name,
sc_fifo<TapAction *> *_tapActionQueue) :
sc_module (name),
tapActionQueue (_tapActionQueue),
stallState (UNKNOWN),
currentScanChain (OR1K_SC_UNDEF)
{
#ifdef NOCACHE
npcCacheIsValid = false; // Always cache NPC
#else
sprCache = new SprCache ();
memCache = new MemCache ();
#endif
 
} // DebugUnitSC ()
 
 
//-----------------------------------------------------------------------------
//! Destructor
 
//! Free up data structures
//-----------------------------------------------------------------------------
DebugUnitSC::~DebugUnitSC ()
{
#ifndef NOCACHE
delete memCache;
delete sprCache;
#endif
 
} // ~DebugUnitSC
 
 
//-----------------------------------------------------------------------------
//! Reset the Debug Unit
 
//! This is just a reset of the JTAG. It is quite possible to reset the debug
//! unit without resetting the whole target.
 
//! @note Must be called from a SystemC thread, because of the use of wait()
//-----------------------------------------------------------------------------
void
DebugUnitSC::resetDebugUnit ()
{
sc_event *done = new sc_event();
TapActionReset *resetAction;
// Create and queue the reset action and wait for it to complete
resetAction = new TapActionReset (done);
tapActionQueue->write (resetAction);
wait (*done);
 
delete resetAction;
delete done;
 
} // resetDebugUnit ()
 
 
//-----------------------------------------------------------------------------
//! Reset the processor
 
//! Read the RISCOP register, OR in the reset bit and write it back.
 
//! After reset, the processor is known to be unstalled.
//-----------------------------------------------------------------------------
void
DebugUnitSC::reset ()
{
writeRiscop (readRiscop () | RISCOP_RESET);
stallState = UNKNOWN;
 
} // reset ()
 
 
//-----------------------------------------------------------------------------
//! Stall the processor
 
//! Read the RISCOP register, OR in the stall bit and write it back.
//-----------------------------------------------------------------------------
void
DebugUnitSC::stall ()
{
writeRiscop (/*readRiscop () |*/ RISCOP_STALL);
stallState = STALLED;
 
} // stall ()
 
 
//-----------------------------------------------------------------------------
//! Unstall the processor
 
//! Read the RISCOP register, AND out the stall bit and write it back. After
//! this the NPC cache will be invalid.
 
//! @note Don't be tempted to read back for confirmation. Single stepping
//! will already have stalled the processor again!
//-----------------------------------------------------------------------------
void
DebugUnitSC::unstall ()
{
writeRiscop (/*readRiscop () & ~RISCOP_STALL*/ 0);
stallState = UNKNOWN;
 
#ifdef NOCACHE
npcCacheIsValid = false; // Always cache NPC
#else
// Clear the caches
sprCache->clear ();
memCache->clear ();
#endif
 
} // unstall ()
 
 
//-----------------------------------------------------------------------------
//! Report if the processor is stalled.
 
//! A stalled processor cannot spontaneously "unstall", so if the stallState
//! flag is STALLED, that value is returned. Otherwise the target is
//! interrogated to determine the status.
 
//! @return TRUE if the processor is known to be stalled
//-----------------------------------------------------------------------------
bool
DebugUnitSC::isStalled ()
{
if (STALLED == stallState)
{
return true;
}
 
uint32_t riscop = readRiscop ();
/* For some reason the reset bit is skipped over somewhere, so we should
just get riscop = 1 if it's stalled */
//stallState = (RISCOP_STALL == (riscop & RISCOP_STALL)) ? STALLED : UNKNOWN;
stallState = riscop ? STALLED : UNKNOWN;
 
return STALLED == stallState;
 
} // isStalled ()
 
 
//-----------------------------------------------------------------------------
//! Read the value of an OpenRISC 1000 Special Purpose Register
 
//! First see if we have the value in the cache, and if so return
//! it. Otherwise, select the RISC_DEBUG scan chain and read from JTAG,
//! storing the result in the cache.
 
//! @param[in] sprNum The SPR to read
 
//! @return The value of the SPR
//-----------------------------------------------------------------------------
uint32_t
DebugUnitSC::readSpr (uint16_t sprNum)
{
uint32_t cachedValue;
 
#ifdef NOCACHE
// Always check NPC cache
if ((STALLED == stallState) && (sprNum == SPR_NPC) && npcCacheIsValid)
{
return npcCachedValue;
}
#else
// Use any cached value if we are stalled.
if ((STALLED == stallState) && sprCache->read (sprNum, cachedValue))
{
return cachedValue; // Already there, no more to do
}
#endif
 
// Read the value
selectDebugModule (OR1K_SC_CPU0);
cachedValue = readJtagReg (sprNum);
 
#ifdef NOCACHE
// Always update the NPC cache
if ((STALLED == stallState) && (sprNum == SPR_NPC))
{
npcCachedValue = cachedValue;
npcCacheIsValid = true;
}
#else
// Update the cache if we are stalled
if (STALLED == stallState)
{
sprCache->write (sprNum, cachedValue, sprNum == SPR_NPC);
}
#endif
 
return cachedValue;
 
} // readSpr ()
 
 
//-----------------------------------------------------------------------------
//! Write the value of an OpenRISC 1000 Special Purpose Register
 
//! First look to see if we are stalled and the value is cached. If the value
//! has not changed, then we need to no more. Otherwise cache the value prior
//! to writing it.
 
//! Select the RISC_DEBUG scan chain and write to JTAG
 
//! @param[in] sprNum The SPR to write
//! @param[in] value The value to write
//-----------------------------------------------------------------------------
void
DebugUnitSC::writeSpr (uint16_t sprNum,
uint32_t value)
{
#ifdef NOCACHE
// Always cache the NPC
if ((STALLED == stallState) && (SPR_NPC == sprNum))
{
// Have we already cached this NPC value?
if (npcCacheIsValid && (value == npcCachedValue))
{
return;
}
else
{
npcCachedValue = value;
npcCacheIsValid = true;
}
}
#else
if (STALLED == stallState)
{
// Have we already cached this value?
uint32_t cachedValue;
if (sprCache->read (sprNum, cachedValue) &&
(value == cachedValue))
{
return; // Already there, no more to do
}
else
{
sprCache->write (sprNum, value, sprNum == SPR_NPC);
}
}
#endif
 
// Write the SPR
selectDebugModule (OR1K_SC_CPU0);
writeJtagReg (sprNum, value);
 
} // writeSpr ()
 
 
//-----------------------------------------------------------------------------
//! AND the contents of an SPR with a value
 
//! A convenience combination of read and write
 
//! @param[in] sprNum The SPR to write
//! @param[in] value The value to AND into the register
//-----------------------------------------------------------------------------
void
DebugUnitSC::andSpr (uint16_t sprNum,
uint32_t value)
{
writeSpr (sprNum, readSpr (sprNum) & value);
 
} // andSpr ()
 
 
//-----------------------------------------------------------------------------
//! OR the contents of an SPR with a value
 
//! A convenience combination of read and write
 
//! @param[in] sprNum The SPR to write
//! @param[in] value The value to OR into the register
//-----------------------------------------------------------------------------
void
DebugUnitSC::orSpr (uint16_t sprNum,
uint32_t value)
{
writeSpr (sprNum, readSpr (sprNum) | value);
 
} // orSpr ()
 
 
//-----------------------------------------------------------------------------
//! Read a 32-bit word from the OpenRISC 1000 memory
 
//! Select the WISHBONE scan chain, then write the register. The data is in
//! model endianness and passed on without modification.
 
//! @todo Provide code to check if the read was from a valid address.
 
//! @param[in] addr The address to read from
 
//! @return The 32-bit value read
//-----------------------------------------------------------------------------
uint32_t
DebugUnitSC::readMem32 (uint32_t addr)
{
uint32_t cachedValue;
 
#ifndef NOCACHE
// Use any cached value if we are stalled.
if ((STALLED == stallState) && memCache->read (addr, cachedValue))
{
return cachedValue; // Already there, no more to do
}
#endif
 
// Read the value
selectDebugModule (OR1K_SC_WISHBONE);
cachedValue = readJtagReg (addr);
 
#ifndef NOCACHE
// Update the cache if we are stalled
if (STALLED == stallState)
{
memCache->write (addr, cachedValue);
}
#endif
 
return cachedValue;
 
} // readMem32 ()
 
 
//-----------------------------------------------------------------------------
//! Write a 32-bit word to the OpenRISC 1000 memory
 
//! Select the WISHBONE scan chain, then write the register. The data is in
//! model endianness and passed on without modification.
 
//! @todo Provide code to check if the write was to a valid address.
 
//! @param[in] addr The address to write to
//! @param[in] value The 32-bit value to write
 
//! @return True if the write was successful. For now all writes are
// successful.
//-----------------------------------------------------------------------------
bool
DebugUnitSC::writeMem32 (uint32_t addr,
uint32_t value)
{
#ifndef NOCACHE
if (STALLED == stallState)
{
// Have we already cached this value?
uint32_t cachedValue;
if (memCache->read (addr, cachedValue) &&
(value == cachedValue))
{
return true; // Already there, no more to do
}
else
{
memCache->write (addr, value); // Write for the future
}
}
#endif
 
// Write the memory
selectDebugModule (OR1K_SC_WISHBONE);
writeJtagReg (addr, value);
 
return true;
 
} // writeMem32 ()
 
 
//-----------------------------------------------------------------------------
//! Read a byte from the OpenRISC 1000 main memory
 
//! All we can get are 32-bits words, so we have to unpick the value.
 
//! The underlying 32-bit routines take target endian arguments and return
//! target endian results. We need to convert to host endianness to access the
//! relevant byte.
 
//! @todo Provide code to check if the read was from a valid address.
 
//! @note Read bytes from memory mapped devices at your peril!
 
//! @param[in] addr The address to read from
//! @return The byte read
//-----------------------------------------------------------------------------
uint8_t
DebugUnitSC::readMem8 (uint32_t addr)
{
uint32_t word = Utils::ttohl (readMem32 (addr & 0xfffffffc));
uint8_t *bytes = (uint8_t *)(&word);
int offset = addr & 0x3;
 
return bytes[offset];
 
} // readMem8 ()
 
 
//-----------------------------------------------------------------------------
//! Write a byte to the OpenRISC 1000 main memory
 
//! All we can get are 32-bits words, so we have to read the current value and
//! construct the new value to write back.
 
//! The underlying 32-bit routines take target endian arguments and return
//! target endian results. We need to convert to host endianness to alter the
//! relevant byte.
 
//! @note Write bytes to memory mapped devices at your peril!
 
//! @todo Provide code to check if the write was to a valid address.
 
//! @param[in] addr The address to write to
//! @param[in] value The byte to write
 
//! @return True if the write was successful. For now all writes are
// successful.
//-----------------------------------------------------------------------------
bool
DebugUnitSC::writeMem8 (uint32_t addr,
uint8_t value)
{
uint32_t currWord = Utils::ttohl (readMem32 (addr & 0xfffffffc));
uint8_t *currBytes = (uint8_t *)(&currWord);
int offset = addr & 0x3;
 
currBytes[offset] = value;
 
return writeMem32 (addr & 0xfffffffc, Utils::htotl (currWord));
 
} // writeMem8 ()
 
 
//-----------------------------------------------------------------------------
//! Get the debug interface CPU0 control register value
 
//! @return The value in the RISCOP register
//-----------------------------------------------------------------------------
uint32_t
DebugUnitSC::readRiscop ()
{
selectDebugModule (OR1K_SC_CPU0);
int drLen; // Size of the data register
uint32_t calc_recv_crc = 0, recv_crc, status_ret;
drLen = 1+4+32+52+4+32;
// Initialize the register fields
uint64_t *dRegIn = new uint64_t [(drLen + 63) / 64];
uint64_t *dRegOut = new uint64_t [(drLen + 63) / 64];
// Write the READ command
clearBits (dRegIn, drLen);
packBits (dRegIn, 0, 1, 0);
packBits (dRegIn, 0+1, 4, BITREV(0x3,4)); // We're reading CPU0 control reg
uint32_t crc32_send = crc32 (dRegIn, 0+1+4, 0);
packBits (dRegIn, 0+1+4, 32, BITREV(crc32_send,32));
 
// Allocate a SystemC completion event
sc_event *done = new sc_event();
// Loop until status is OK and CRCs match.
do
{
TapActionDRScan *dRScan = new TapActionDRScan (done, dRegIn, drLen);
tapActionQueue->write (dRScan);
wait (*done);
dRScan->getDRegOut (dRegOut);
delete dRScan;
status_ret = unpackBits (dRegOut,1+4+32+52,4);
calc_recv_crc = crc32(dRegOut,52+4,1+4+32);
recv_crc = BITREV(unpackBits (dRegOut,1+4+32+52+4,32),32);
}
while ((0 != status_ret) || ( calc_recv_crc != recv_crc));
 
// All done
uint32_t res = BITREV(unpackBits (dRegOut, (1+4+32),2),2);
delete [] dRegIn;
delete [] dRegOut;
delete done;
return res;
} // readRiscop ()
 
 
//-----------------------------------------------------------------------------
//! Set the RISCOP control register
 
//! Convenience function. Select the REGISTER scan chain, write the new value.
 
//! @param[in] value The value to write into the RISCOP register
//-----------------------------------------------------------------------------
void
DebugUnitSC::writeRiscop (uint32_t value)
{
selectDebugModule (OR1K_SC_CPU0);
int drLen; // Size of the data register
uint32_t calc_recv_crc = 0, recv_crc, status_ret;
drLen = 1+4+32+52+4+32;
// Initialize the register fields
uint64_t *dRegIn = new uint64_t [(drLen + 63) / 64];
uint64_t *dRegOut = new uint64_t [(drLen + 63) / 64];
// Write the READ command
clearBits (dRegIn, drLen);
packBits (dRegIn, 0, 1, 0);
packBits (dRegIn, 0+1, 4, BITREV(0x4,4)); // We're writing CPU0 control reg
packBits (dRegIn, 5, 1, value&RISCOP_RESET); // First bit is reset
packBits (dRegIn, 6, 1, (value&RISCOP_STALL)>>1); // Next bit is stall
/* Next 50 bits should be zero */
uint32_t crc32_send = crc32 (dRegIn, 1+4+52, 0);
packBits (dRegIn, 1+4+52, 32, BITREV(crc32_send,32));
 
// Allocate a SystemC completion event
sc_event *done = new sc_event();
// Loop until status is OK and CRCs match.
do
{
TapActionDRScan *dRScan = new TapActionDRScan (done, dRegIn, drLen);
tapActionQueue->write (dRScan);
wait (*done);
dRScan->getDRegOut (dRegOut);
delete dRScan;
status_ret = unpackBits (dRegOut,1+4+32+52,4);
calc_recv_crc = crc32(dRegOut,4,1+4+52+32);
recv_crc = BITREV(unpackBits (dRegOut,1+4+52+32+4,32),32);
}
while ((0 != status_ret) || ( calc_recv_crc != recv_crc));
delete [] dRegIn;
delete [] dRegOut;
delete done;
 
} // writeRiscop ()
 
 
//-----------------------------------------------------------------------------
//! Select a module attached to the debug module
 
//! @note Must be called from a SystemC thread, because of the use of wait()
 
//! @param[in] chain The desired module
//-----------------------------------------------------------------------------
void
DebugUnitSC::selectDebugModule (int module)
{
 
if (module == currentScanChain)
{
return;
}
else
{
currentScanChain = module;
}
 
sc_event *done = new sc_event();
TapActionIRScan *iRScan;
TapActionDRScan *dRScan;
 
// Create and queue the IR-Scan action for DEBUG (no CRC)
iRScan = new TapActionIRScan (done, DEBUG_IR, JTAG_IR_LEN);
tapActionQueue->write (iRScan);
wait (*done);
 
delete iRScan;
 
// Initialize the register fields
uint64_t *dRegIn = new uint64_t [(DUSEL_DR_LEN + 63) / 64];
uint64_t *dRegOut = new uint64_t [(DUSEL_DR_LEN + 63) / 64];
 
clearBits (dRegIn, DUSEL_DR_LEN);
packBits (dRegIn, DUSEL_SEL_OFF, DUSEL_SEL_LEN, 0x1);
packBits (dRegIn, DUSEL_OPCODE_OFF, DUSEL_OPCODE_LEN, bit_reverse_data(module,4));
uint32_t crc32_send = crc32 (dRegIn, DUSEL_CRC_OFF, 0);
packBits (dRegIn, DUSEL_CRC_OFF, DUSEL_CRC_LEN, bit_reverse_data(crc32_send,32) );
uint32_t calc_recv_crc = 0, recv_crc, status_ret;
// Loop until status is OK and CRCs match.
do
{
TapActionDRScan *dRScan = new TapActionDRScan (done, dRegIn, DUSEL_DR_LEN);
tapActionQueue->write (dRScan);
wait (*done);
dRScan->getDRegOut (dRegOut);
delete dRScan;
status_ret = unpackBits (dRegOut, DUSEL_RESP_STATUS_OFF, DUSEL_RESP_STATUS_LEN);
calc_recv_crc = crc32(dRegOut, DUSEL_RESP_STATUS_LEN, DUSEL_RESP_STATUS_OFF);
recv_crc = bit_reverse_data(unpackBits (dRegOut, DUSEL_RESP_CRC_OFF, DUSEL_RESP_CRC_LEN),32);
}
while ((0 != status_ret) || ( calc_recv_crc != recv_crc));
 
delete [] dRegIn;
delete [] dRegOut;
delete done;
 
} // selectDebugModule()
 
//-----------------------------------------------------------------------------
//! Read a 32-bit value via the debug interface
 
//! @note Must be called from a SystemC thread, because of the use of wait()
 
//! @param[in] addr The address of the register
 
//! @return The register value read
//-----------------------------------------------------------------------------
uint32_t
DebugUnitSC::readJtagReg (uint32_t addr)
{
int drLen; // Size of the data register
uint32_t calc_recv_crc = 0, recv_crc, status_ret;
drLen = 125; // Size of write command command (bigger than data read)
// Initialize the register fields
uint64_t *dRegIn = new uint64_t [(drLen + 63) / 64];
uint64_t *dRegOut = new uint64_t [(drLen + 63) / 64];
// Write the READ command
clearBits (dRegIn, drLen);
packBits (dRegIn, 0, 1, 0);
packBits (dRegIn, 0+1, 4, BITREV(0x2,4)); // We're writing a command
packBits (dRegIn, 1+4, 4, BITREV(0x6,4)); // Access type, 0x6 = 32-bit READ
packBits (dRegIn, 1+4+4, 32, BITREV(addr,32)); // Address
packBits (dRegIn, 1+4+4+32, 16, BITREV(0x3,16)); // Length (always 32-bit,n=(32/8)-1=3)
uint32_t crc32_send = crc32 (dRegIn, 1+4+4+32+16, 0);
packBits (dRegIn, 1+4+4+32+16, 32, BITREV(crc32_send,32));
 
// Allocate a SystemC completion event
sc_event *done = new sc_event();
// Loop until status is OK and CRCs match.
do
{
TapActionDRScan *dRScan = new TapActionDRScan (done, dRegIn, 125);
tapActionQueue->write (dRScan);
wait (*done);
dRScan->getDRegOut (dRegOut);
delete dRScan;
status_ret = unpackBits (dRegOut,1+4+4+32+16+32,4);
calc_recv_crc = crc32(dRegOut,4,1+4+4+32+16+32);
recv_crc = BITREV(unpackBits (dRegOut,1+4+4+32+16+32+4,32),32);
}
while ((0 != status_ret) || ( calc_recv_crc != recv_crc));
 
clearBits (dRegIn, drLen);
packBits (dRegIn, 0, 1, 0);
packBits (dRegIn, 0+1, 4, 0x0); // We're GO'ing command
crc32_send = crc32 (dRegIn,1+4,0);
packBits (dRegIn, 1+4, 32, BITREV(crc32_send,32)); // CRC
uint32_t result;
// Loop until status is OK and CRCs match.
do
{
TapActionDRScan *dRScan = new TapActionDRScan (done, dRegIn, (1+4+32+36+((3+1)*8)));
tapActionQueue->write (dRScan);
wait (*done);
dRScan->getDRegOut (dRegOut);
delete dRScan;
status_ret = BITREV(unpackBits (dRegOut,1+4+32+((3+1)*8),4),4);
if (status_ret)
{
printf("readJtagReg(): Addr: 0x%.8x Status err: 0x%x\n",addr,status_ret);
result = 0;
break;
}
calc_recv_crc = crc32(dRegOut,((3+1)*8)+4,1+4+32);
recv_crc = BITREV(unpackBits (dRegOut,1+4+32+((3+1)*8)+4,32),32);
result = BITREV(unpackBits (dRegOut, (1+4+32), ((3+1)*8)),32);
 
}
while ((0 != status_ret) || ( calc_recv_crc != recv_crc));
// All done
delete [] dRegIn;
delete [] dRegOut;
delete done;
return result;
 
} // readJtagReg ()
 
 
//-----------------------------------------------------------------------------
//! Write a 32-bit value via the debug interface
 
//! @note Must be called from a SystemC thread, because of the use of wait()
 
//! @param[in] addr The address of the register
//! @param[in] data The register data to write
//-----------------------------------------------------------------------------
void
DebugUnitSC::writeJtagReg (uint32_t addr,
uint32_t data)
{
int drLen; // Size of the data register
uint32_t calc_recv_crc = 0, recv_crc, status_ret;
drLen = 125; // Size of write command command (bigger than data read)
// Initialize the register fields
uint64_t *dRegIn = new uint64_t [(drLen + 63) / 64];
uint64_t *dRegOut = new uint64_t [(drLen + 63) / 64];
// Write the READ command
clearBits (dRegIn, drLen);
packBits (dRegIn, 0, 1, 0);
packBits (dRegIn, 0+1, 4, BITREV(0x2,4)); // We're writing a command
packBits (dRegIn, 1+4, 4, BITREV(0x2,4)); // Access type, 0x2 = 32-bit WRITE
packBits (dRegIn, 1+4+4, 32, BITREV(addr,32)); // Address
packBits (dRegIn, 1+4+4+32, 16, BITREV(0x3,16)); // Length (always 32-bit,n=(32/8)-1=3)
uint32_t crc32_send = crc32 (dRegIn, 1+4+4+32+16, 0);
packBits (dRegIn, 1+4+4+32+16, 32, BITREV(crc32_send,32));
 
// Allocate a SystemC completion event
sc_event *done = new sc_event();
// Loop until status is OK and CRCs match.
do
{
TapActionDRScan *dRScan = new TapActionDRScan (done, dRegIn, 125);
tapActionQueue->write (dRScan);
wait (*done);
dRScan->getDRegOut (dRegOut);
delete dRScan;
status_ret = unpackBits (dRegOut,1+4+4+32+16+32,4);
calc_recv_crc = crc32(dRegOut,4,1+4+4+32+16+32);
recv_crc = BITREV(unpackBits (dRegOut,1+4+4+32+16+32+4,32),32);
}
while ((0 != status_ret) || ( calc_recv_crc != recv_crc));
clearBits (dRegIn, drLen);
packBits (dRegIn, 0, 1, 0);
packBits (dRegIn, 0+1, 4, 0x0); // We're GO'ing command
packBits (dRegIn, 0+1+4, 32, BITREV(data,32)); // Add in data
crc32_send = crc32 (dRegIn,1+4+32,0);
packBits (dRegIn, 1+4+32, 32, BITREV(crc32_send,32)); // CRC
// Loop until status is OK and CRCs match.
do
{
TapActionDRScan *dRScan = new TapActionDRScan (done, dRegIn, (1+4+((3+1)*8)+32+36));
tapActionQueue->write (dRScan);
wait (*done);
dRScan->getDRegOut (dRegOut);
delete dRScan;
status_ret = unpackBits (dRegOut,1+4+32+32,4);
calc_recv_crc = crc32(dRegOut,4,1+4+32+32);
recv_crc = BITREV(unpackBits (dRegOut,1+4+32+32+4,32),32);
}
while ((0 != status_ret) || ( calc_recv_crc != recv_crc));
delete [] dRegIn;
delete [] dRegOut;
delete done;
 
} // writeJtagReg ()
 
 
//-----------------------------------------------------------------------------
//! Clear the bits in a data register
 
//! We always clear whole 64-bit words, not just the minimum number of
//! bytes. It saves all sorts of confusion when debugging code.
 
//! @note It is the caller's responsibility to make sure the date register
//! array is large enough.
 
//! @param[in,out] regArray The data register to clear
//! @param[in] regBits Size of the data register (in bits)
//-----------------------------------------------------------------------------
void
DebugUnitSC::clearBits (uint64_t regArray[],
int regBits)
{
memset ((char *)regArray, 0, ((regBits + 63) / 64) * 8);
 
} // clearBits ()
 
 
//-----------------------------------------------------------------------------
//! Set a bit field in a data register
 
//! The field is cleared, the supplied value masked and then ored into the
//! vector.
 
//! @note It is the caller's responsibility to make sure the date register
//! array is large enough.
 
//! @param[in,out] regArray The data register
//! @param[in] fieldOffset Start of the field (in bits)
//! @param[in] fieldBits Size of the field (in bits)
//! @param[in] fieldVal Value to set in the field
//-----------------------------------------------------------------------------
void
DebugUnitSC::packBits (uint64_t regArray[],
int fieldOffset,
int fieldBits,
uint64_t fieldVal)
{
fieldVal &= (1ULL << fieldBits) - 1ULL; // Mask the supplied value
 
int startWord = fieldOffset / 64;
int endWord = (fieldOffset + fieldBits - 1) / 64;
 
fieldOffset = fieldOffset % 64; // Now refers to target word
 
// Deal with the startWord. Get enough bits for the mask and put them in the
// right place
uint64_t startMask = ((1ULL << fieldBits) - 1ULL) << fieldOffset;
 
regArray[startWord] &= ~startMask;
regArray[startWord] |= fieldVal << fieldOffset;
 
// If we were all in one word, we can give up now.
if (startWord == endWord)
{
return;
}
 
// Deal with the endWord. Get enough bits for the mask. No need to shift
// these up - they're always at the bottom of the word
int bitsToDo = (fieldOffset + fieldBits) % 64;
uint64_t endMask = (1ULL << bitsToDo) - 1ULL;
 
regArray[endWord] &= ~endMask;
regArray[endWord] |= fieldVal >> (fieldBits - bitsToDo);
 
} // packBits ()
 
 
//-----------------------------------------------------------------------------
//! Extract a bit field from a data register
 
//! The field is cleared, the supplied value masked and then ored into the
//! vector.
 
//! @note It is the caller's responsibility to make sure the date register
//! array is large enough.
 
//! @param[in,out] regArray The data register
//! @param[in] fieldOffset Start of the field (in bits)
//! @param[in] fieldBits Size of the field (in bits)
 
//! @return The value in the field
//-----------------------------------------------------------------------------
uint64_t
DebugUnitSC::unpackBits (uint64_t regArray[],
int fieldOffset,
int fieldBits)
{
int startWord = fieldOffset / 64;
int endWord = (fieldOffset + fieldBits - 1) / 64;
 
fieldOffset = fieldOffset % 64; // Now refers to target word
 
// Deal with the startWord. Get enough bits for the mask and put them in the
// right place
uint64_t startMask = ((1ULL << fieldBits) - 1ULL) << fieldOffset;
uint64_t res = (regArray[startWord] & startMask) >> fieldOffset;
 
// If we were all in one word, we can give up now.
if (startWord == endWord)
{
res &= (1ULL << fieldBits) - 1ULL; // Mask off any unwanted bits
return res;
}
 
// Deal with the endWord. Get enough bits for the mask. No need to shift
// these up - they're always at the bottom of the word
int bitsToDo = (fieldOffset + fieldBits) % 64;
uint64_t endMask = (1ULL << bitsToDo) - 1ULL;
 
res = res | ((regArray[endWord] & endMask) << (fieldBits - bitsToDo));
res &= (1ULL << fieldBits) - 1ULL; // Mask off any unwanted bits
return res;
 
} // unpackBits ()
 
 
//-----------------------------------------------------------------------------
//! Compute CRC-8-ATM
 
//! The data is in an array of uint64_t, for which we use the first size bits
//! to compute the CRC.
 
//! @Note I am using the same algorithm as the ORPSoC debug unit, but I
//! believe its function is broken! I don't believe the data bit should
//! feature in the computation of bits 2 & 1 of the new CRC.
 
//! @Note I've realized that this is an algorithm for LSB first, so maybe it
//! is correct!
 
//! @param dataArray The array of data whose CRC is desired
//! @param size The number of bits in the data
//-----------------------------------------------------------------------------
uint8_t
DebugUnitSC::crc8 (uint64_t dataArray[],
int size)
{
uint8_t crc = 0;
 
for (int i = 0; i < size; i++)
{
uint8_t d = (dataArray[i / 64] >> (i % 64)) & 1;
uint8_t oldCrc7 = (crc >> 7) & 1;
uint8_t oldCrc1 = (crc >> 1) & 1;
uint8_t oldCrc0 = (crc >> 0) & 1;
uint8_t newCrc2 = d ^ oldCrc1 ^ oldCrc7; // Why d?
uint8_t newCrc1 = d ^ oldCrc0 ^ oldCrc7; // Why d?
uint8_t newCrc0 = d ^ oldCrc7;
 
crc = ((crc << 1) & 0xf8) | (newCrc2 << 2) | (newCrc1 << 1) | newCrc0;
}
 
return crc;
 
} // crc8 ()
 
/* Crc of current read or written data. */
uint32_t crc_r, crc_w = 0;
 
/* Generates new crc, sending in new bit input_bit */
uint32_t
DebugUnitSC::crc32(uint64_t dataArray[],
int size,
int offset)
{
uint32_t crc = 0xffffffff;
for (int i = offset; i < size+offset; i++)
{
uint32_t d = ((dataArray[i / 64] >> (i % 64)) & 1) ? 0xfffffff : 0x0000000;
uint32_t crc_32 = ((crc >> 31)&1) ? 0xfffffff : 0x0000000;
crc <<= 1;
crc = crc ^ ((d ^ crc_32) & DBG_CRC32_POLY);
}
 
return crc;
}
 
uint32_t
DebugUnitSC::bit_reverse_swar_2(uint32_t x)
{
return (((x&0xaaaaaaaa)>>1)|((x&0x55555555)<<1));
}
uint32_t
DebugUnitSC::bit_reverse_swar_4(uint32_t x)
{
x=(((x&0xaaaaaaaa)>>1)|((x&0x55555555)<<1));
x=(((x&0xcccccccc)>>2)|((x&0x33333333)<<2));
return x;
}
uint32_t
DebugUnitSC::bit_reverse_swar_8(uint32_t x)
{
x=(((x&0xaaaaaaaa)>>1)|((x&0x55555555)<<1));
x=(((x&0xcccccccc)>>2)|((x&0x33333333)<<2));
x=(((x&0xf0f0f0f0)>>4)|((x&0x0f0f0f0f)<<4));
return x;
}
uint32_t
DebugUnitSC::bit_reverse_swar_16(uint32_t x)
{
x=(((x&0xaaaaaaaa)>>1)|((x&0x55555555)<<1));
x=(((x&0xcccccccc)>>2)|((x&0x33333333)<<2));
x=(((x&0xf0f0f0f0)>>4)|((x&0x0f0f0f0f)<<4));
x=(((x&0xff00ff00)>>8)|((x&0x00ff00ff)<<8));
return x;
}
uint32_t
DebugUnitSC::bit_reverse_swar_32(uint32_t x)
{
x=(((x&0xaaaaaaaa)>>1)|((x&0x55555555)<<1));
x=(((x&0xcccccccc)>>2)|((x&0x33333333)<<2));
x=(((x&0xf0f0f0f0)>>4)|((x&0x0f0f0f0f)<<4));
x=(((x&0xff00ff00)>>8)|((x&0x00ff00ff)<<8));
x=(((x&0xffff0000)>>16)|((x&0x0000ffff)<<16)); // We could be on 64-bit arch!
return x;
}
uint32_t
DebugUnitSC::bit_reverse_data(uint32_t data, int length){
if (length == 2) return bit_reverse_swar_2(data);
if (length == 4) return bit_reverse_swar_4(data);
if (length == 8) return bit_reverse_swar_8(data);
if (length == 16) return bit_reverse_swar_16(data);
if (length == 32) return bit_reverse_swar_32(data);
// Long and laborious way - hopefully never gets called anymore!
uint32_t reverse=0;
for (int i=0;i<length;i++) reverse |= (((data>>i)&1)<<(length-1-i));
return reverse;
}
/src/TapActionDRScan.cpp
0,0 → 1,589
// ----------------------------------------------------------------------------
 
// TAP DR-Scan action: implementation
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
#include <iostream>
#include <stdio.h>
#include "TapActionDRScan.h"
#include "TapStateMachine.h"
 
 
//! Constructor for "large" DR registers
 
//! Sets up the superclass with the SystemC completion event and initializes
//! our state as appropriate.
 
//! This constructor represents large registers as an array of uint64_t, with
//! least significant bits in the lowest numbered element, and any odd bits in
//! the highest numbered element.
 
//! However if we are presented with an array that represents a "small"
//! (i.e. up to 64-bit) register, we will store it efficiently.
 
//! @param[in] doneEvent SystemC event to be signalled when this action is
//! complete.
//! @param[in] _dRegInArray The register to shift in.
//! @param[in] _dRegSize Size in bits of the register to shift in.
 
TapActionDRScan::TapActionDRScan (sc_core::sc_event *_doneEvent,
uint64_t *_dRegInArray,
int _dRegSize
) :
TapAction (_doneEvent),
dRegBitSize (_dRegSize),
dRegWordSize ((_dRegSize + 63) / 64),
goToPauseState(0),
bitsBeforePause(0),
bitsShifted (0),
dRScanState (SHIFT_DR_PREPARING)
{
// Small registers are represented simply. Large registers are copied to a
// local instance (since we destroy dRegIn when shifting it)
 
if (1 == dRegWordSize)
{
dRegIn = _dRegInArray[0];
dRegOut = 0;
}
else
{
dRegInArray = new uint64_t [dRegWordSize];
dRegOutArray = new uint64_t [dRegWordSize];
 
// Copy in the in array and zero the out array
for (int i = 0; i < dRegWordSize; i++)
{
dRegInArray[i] = _dRegInArray[i];
dRegOutArray[i] = 0;
}
 
// Create a mask for the top word
int maskBits = ((dRegBitSize - 1) % 64) + 1;
topMask = (1ULL << maskBits) - 1ULL;
}
} // TapActionDRScan ()
 
 
//! Constructor for small DR registers
 
//! Sets up the superclass with the SystemC completion event and initializes
//! our state as appropriate.
 
//! This constructor represents small registers in a single uint64_t
 
//! @param[in] doneEvent SystemC event to be signalled when this action is
//! complete.
//! @param[in] _dRegIn The register to shift in.
//! @param[in] _dRegSize Size in bits of the register to shift in. Must be no
//! greater than 64, or we give a rude message and set
//! the value to 64 anyway.
 
TapActionDRScan::TapActionDRScan (sc_core::sc_event *_doneEvent,
uint64_t _dRegIn,
int _dRegSize) :
TapAction (_doneEvent),
dRegBitSize (_dRegSize),
dRegWordSize (1),
goToPauseState(0),
bitsBeforePause(0),
bitsShifted (0),
dRScanState (SHIFT_DR_PREPARING)
{
// Print a rude message if we are not small
if (dRegBitSize > 64)
{
std::cerr << "Simple DR size reduced to 64 bits" << std::endl;
dRegBitSize = 64;
}
 
// Simple representation
dRegIn = _dRegIn;
dRegOut = 0;
 
} // TapActionDRScan ()
 
//! Constructor for "large" DR registers using special PAUSE state
 
//! Sets up the superclass with the SystemC completion event and initializes
//! our state as appropriate.
 
//! This constructor represents large registers as an array of uint64_t, with
//! least significant bits in the lowest numbered element, and any odd bits in
//! the highest numbered element.
 
//! However if we are presented with an array that represents a "small"
//! (i.e. up to 64-bit) register, we will store it efficiently.
 
//! @param[in] doneEvent SystemC event to be signalled when this action is
//! complete.
//! @param[in] _dRegInArray The register to shift in.
//! @param[in] _dRegSize Size in bits of the register to shift in.
//! @param[in] _goToPauseState Switch determining if we go to PAUSE state after _bitsBeforePauseState and poll for TDO=0
//! @param[in] _bitsBeforePauseState Number of bits to shift in before going to shift pause state and polling TDO, indicating transaction has completed
 
TapActionDRScan::TapActionDRScan (sc_core::sc_event *_doneEvent,
uint64_t *_dRegInArray,
int _dRegSize,
int _goToPauseState,
int _bitsBeforePauseState
) :
TapAction (_doneEvent),
dRegBitSize (_dRegSize),
dRegWordSize ((_dRegSize + 63) / 64),
goToPauseState(_goToPauseState),
bitsBeforePause(_bitsBeforePauseState),
pauseStateCount(0),
bitsShifted (0),
dRScanState (SHIFT_DR_PREPARING)
{
// Small registers are represented simply. Large registers are copied to a
// local instance (since we destroy dRegIn when shifting it)
 
if (1 == dRegWordSize)
{
dRegIn = _dRegInArray[0];
dRegOut = 0;
}
else
{
dRegInArray = new uint64_t [dRegWordSize];
dRegOutArray = new uint64_t [dRegWordSize];
 
// Copy in the in array and zero the out array
for (int i = 0; i < dRegWordSize; i++)
{
dRegInArray[i] = _dRegInArray[i];
dRegOutArray[i] = 0;
}
 
// Create a mask for the top word
int maskBits = ((dRegBitSize - 1) % 64) + 1;
topMask = (1ULL << maskBits) - 1ULL;
}
} // TapActionDRScan ()
 
 
//! Constructor for small DR registers using special PAUSE state
 
//! Sets up the superclass with the SystemC completion event and initializes
//! our state as appropriate.
 
//! This constructor represents small registers in a single uint64_t
 
//! @param[in] doneEvent SystemC event to be signalled when this action is
//! complete.
//! @param[in] _dRegIn The register to shift in.
//! @param[in] _dRegSize Size in bits of the register to shift in. Must be no
//! greater than 64, or we give a rude message and set
//! the value to 64 anyway.
//! @param[in] _goToPauseState Switch determining if we go to PAUSE state after _bitsBeforePauseState and poll for TDO=0
//! @param[in] _bitsBeforePauseState Number of bits to shift in before going to shift pause state and polling TDO, indicating transaction has completed
 
 
TapActionDRScan::TapActionDRScan (sc_core::sc_event *_doneEvent,
uint64_t _dRegIn,
int _dRegSize,
int _goToPauseState,
int _bitsBeforePauseState
) :
TapAction (_doneEvent),
dRegBitSize (_dRegSize),
dRegWordSize (1),
goToPauseState(_goToPauseState),
bitsBeforePause(_bitsBeforePauseState),
pauseStateCount(0),
bitsShifted (0),
dRScanState (SHIFT_DR_PREPARING)
{
// Print a rude message if we are not small
if (dRegBitSize > 64)
{
std::cerr << "Simple DR size reduced to 64 bits" << std::endl;
dRegBitSize = 64;
}
 
// Simple representation
dRegIn = _dRegIn;
dRegOut = 0;
 
} // TapActionDRScan ()
 
 
 
 
//! Destructor.
 
//! If we allocated them, free the large registers
 
TapActionDRScan::~TapActionDRScan ()
{
if (dRegWordSize > 1)
{
delete [] dRegInArray;
delete [] dRegOutArray;
}
} // ~TapActionDRScan ()
 
 
//! Process the Shift-DR action
 
//! This drives the DR-Scan state. We can only do this if we have the TAP
//! state machine in a consistent state, which in turn is only possible if we
//! have been through a reset cycle.
 
//! If the state machine shows it has yet to be through a reset cycle, we
//! drive that cycle, after issuing a warning. This functionality is provided
//! by the parent class, TapAction::.
 
//! @param[in] tapStateMachine The TAP state machine with which this action
//! is associated.
//! @param[out] tdi The value to drive on TDI
//! @param[in] tdo The value currently on TDO
//! @param[out] tms The value to drive on TMS
 
//! @return True if the action is complete
 
bool
TapActionDRScan::process (TapStateMachine *tapStateMachine,
bool &tdi,
bool tdo,
bool &tms)
{
// Ensure we are in a consistent state. If not then we'll have moved towards
// it and can return with the given tms
if (!checkResetDone (tapStateMachine, tms, true))
{
return false;
}
if (goToPauseState)
{
switch (dRScanState)
{
case SHIFT_DR_PREPARING:
// Are we in the Shift-DR state yet?
if (!tapStateMachine->targetState (TAP_SHIFT_DR, tms))
{
return false; // Not there. Accept the TMS value
}
else
{
dRScanState = SHIFT_DR_SHIFTING_BEFORE_PAUSE; // Drop through
}
case SHIFT_DR_SHIFTING_BEFORE_PAUSE:
// Are we still shifting stuff?
if (bitsShifted < bitsBeforePause)
{
// We are in the Shift-DR state. Another bit about to be done, so
// increment the count
bitsShifted++;
// Set the TDI value. In a routine to keep this tidy.
tdi = shiftDRegOut ();
// Record the TDO value. This is always a cycle late, so we ignore
// it the first time. The value shifts in from the top.
if (bitsShifted > 1)
{
shiftDRegIn (tdo);
}
// TMS is 0 to keep us here UNLESS this is the last bit, in which case
// it is 1 to move us into Exit1-DR.
tms = (bitsShifted == bitsBeforePause);
// Not done until we've updated
return false;
}
else
{
// Capture the last TDO bit
shiftDRegIn (tdo);
// Now lower TMS to go to PAUSE_DR
tms = false;
dRScanState = SHIFT_DR_SHIFTING_PAUSE;
}
case SHIFT_DR_SHIFTING_PAUSE:
{
if (!tapStateMachine->targetState (TAP_PAUSE_DR, tms))
{
return false; // Not there. Accept the TMS value
}
if ( pauseStateCount++ < 3)
return false;
// Sit in DR_PAUSE state and cycle until TDO is low
// tms starts false, should get set to true on the cycle
// tdo goes low, then the next cycle we go back to SHIFT_DR
// and we return so tms isn't set again.
if (!tdo)
{
tms = true;
dRScanState = SHIFT_DR_EXIT2;
return false;
}
}
case SHIFT_DR_EXIT2:
{
tms = false;
shiftDRegIn (0);
dRScanState = SHIFT_DR_SHIFTING_AFTER_PAUSE;
return false;
}
case SHIFT_DR_SHIFTING_AFTER_PAUSE:
{
if (bitsShifted < dRegBitSize)
{
// We are in the Shift-DR state. Another bit about to be done, so
// increment the count
bitsShifted++;
// Set the TDI value. In a routine to keep this tidy.
tdi = shiftDRegOut ();
//printf("shifting after pause (%d+32=%d) %d of %d tdo=%d\n",bitsBeforePause,bitsBeforePause+32, bitsShifted, dRegBitSize,(tdo) ? 1 : 0);
shiftDRegIn (tdo);
// TMS is 0 to keep us here UNLESS this is the last bit, in which case
// it is 1 to move us into Exit1-DR.
tms = (bitsShifted == dRegBitSize);
// Not done until we've updated
return false;
}
else
{
// Capture the last TDO bit
shiftDRegIn (tdo);
dRScanState = SHIFT_DR_UPDATING; // Drop through
}
}
case SHIFT_DR_UPDATING:
// Are we still trying to update?
if (!tapStateMachine->targetState (TAP_UPDATE_DR, tms))
{
return false; // Not there. Accept the TMS value
}
else
{
return true; // All done
}
}
}
else
{
switch (dRScanState)
{
case SHIFT_DR_PREPARING:
// Are we in the Shift-DR state yet?
if (!tapStateMachine->targetState (TAP_SHIFT_DR, tms))
{
return false; // Not there. Accept the TMS value
}
else
{
dRScanState = SHIFT_DR_SHIFTING; // Drop through
}
case SHIFT_DR_SHIFTING:
// Are we still shifting stuff?
if (bitsShifted < dRegBitSize)
{
// We are in the Shift-DR state. Another bit about to be done, so
// increment the count
bitsShifted++;
// Set the TDI value. In a routine to keep this tidy.
tdi = shiftDRegOut ();
// Record the TDO value. This is always a cycle late, so we ignore
// it the first time. The value shifts in from the top.
if (bitsShifted > 1)
{
shiftDRegIn (tdo);
}
// TMS is 0 to keep us here UNLESS this is the last bit, in which case
// it is 1 to move us into Exit1-DR.
tms = (bitsShifted == dRegBitSize);
// Not done until we've updated
return false;
}
else
{
// Capture the last TDO bit
shiftDRegIn (tdo);
dRScanState = SHIFT_DR_UPDATING; // Drop through
}
case SHIFT_DR_UPDATING:
// Are we still trying to update?
if (!tapStateMachine->targetState (TAP_UPDATE_DR, tms))
{
return false; // Not there. Accept the TMS value
}
else
{
return true; // All done
}
}
}
} // process ()
 
 
//! Get the shifted out value.
 
//! This version works with large values.
 
//! @param[out] dRegArray Array for the result
void
TapActionDRScan::getDRegOut (uint64_t dRegArray[])
{
if (1 == dRegWordSize)
{
dRegArray[0] = dRegOut;
}
else
{
for (int i = 0 ; i < dRegWordSize; i++)
{
dRegArray[i] = dRegOutArray[i];
}
}
} // getDRegOut ()
 
 
//! Get the shifted out value.
 
//! This version is for small values. For large values it silently returns the
//! bottom 64 bits only.
 
//! @todo Should we give an error. Or is it useful to allow efficient access
//! to the bottom 64 bits?
 
//! @return The value shifted out (or the bottom 64 bits thereof if the
//! register is "large").
uint64_t
TapActionDRScan::getDRegOut ()
{
if (1 == dRegWordSize)
{
return dRegOut;
}
else
{
return dRegOutArray[0];
}
} // getDRegOut ()
 
 
//! Utility to shift the bottom bit out of the dReg.
 
//! Two flavours depending on whether we have a "small" register
 
//! @return The bit shifted out.
bool
TapActionDRScan::shiftDRegOut ()
{
if (1 == dRegWordSize) // "Small" register
{
bool res = dRegIn & 1;
dRegIn >>= 1;
return res;
}
else // "Large" register
{
bool res = (dRegInArray[0] & 1) == 1;
 
// Shift all but the first word along
for (int i = 0; i < (dRegWordSize - 1); i++)
{
dRegInArray[i] = (dRegInArray[i] >> 1) | (dRegInArray[i+1] << 63);
}
 
// Shift the first word
dRegInArray[dRegWordSize - 1] >>= 1;
 
return res;
}
} // shiftDRegOut ()
 
 
//! Utility to shift the top bit into the dReg.
 
//! Two flavours depending on whether we have a "small" register
 
//! @param bitIn The bit to shift in the top
void
TapActionDRScan::shiftDRegIn (bool bitIn)
{
if (1 == dRegWordSize) // "Small" register
{
dRegOut >>= 1; // Move all the existing bits right
 
if (bitIn) // OR any new bit in
{
uint64_t tmpBit = 1ULL << (dRegBitSize - 1);
dRegOut |= tmpBit;
}
}
else // "Large" register
{
// Shift all but the first word along
for (int i = 0; i < (dRegWordSize - 1); i++)
{
dRegOutArray[i] >>= 1;
dRegOutArray[i] |= dRegOutArray[i+1] << 63;
}
 
// The first word is shifted and the new bit masked in
dRegOutArray[dRegWordSize - 1] >>= 1;
dRegOutArray[dRegWordSize - 1] |= bitIn ? (topMask + 1) >> 1 : 0;
}
} // shiftDRegIn ()
/src/MpHash.cpp
0,0 → 1,187
// ----------------------------------------------------------------------------
 
// Matchpoint hash table: definition
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: MpHash.cpp 331 2009-03-12 17:01:48Z jeremy $
 
#include <cstdlib>
 
#include "MpHash.h"
 
 
//! Constructor
 
//! Allocate the hash table
//! @param[in] size Number of slots in the hash table. Defaults to
//! DEFAULT_MP_HASH_SIZE.
MpHash::MpHash (int _size) :
size (_size)
{
// Allocate and clear the hash table
hashTab = new MpEntry *[size];
 
for (int i = 0; i < size; i++)
{
hashTab[i] = NULL;
}
} // MpHash ()
 
 
//! Destructor
 
//! Free the hash table
MpHash::~MpHash ()
{
delete [] hashTab;
 
} // ~MpHash ()
 
 
//! Add an entry to the hash table
 
//! Add the entry if it wasn't already there. If it was there do nothing. The
//! match just be on type and addr. The instr need not match, since if this is
//! a duplicate insertion (perhaps due to a lost packet) they will be
//! different.
 
//! @note This method allocates memory. Care must be taken to delete it when
//! done.
 
//! @param[in] type The type of matchpoint
//! @param[in] addr The address of the matchpoint
//! @para[in] instr The instruction to associate with the address
void
MpHash::add (MpType type,
uint32_t addr,
uint32_t instr)
{
int hv = addr % size;
MpEntry *curr;
 
// See if we already have the entry
for(curr = hashTab[hv]; NULL != curr; curr = curr->next)
{
if ((type == curr->type) && (addr == curr->addr))
{
return; // We already have the entry
}
}
 
// Insert the new entry at the head of the chain
curr = new MpEntry ();
curr->type = type;
curr->addr = addr;
curr->instr = instr;
curr->next = hashTab[hv];
 
hashTab[hv] = curr;
 
} // add ()
 
 
//!Look up an entry in the matchpoint hash table
 
//! The match must be on type AND addr.
 
//! @param[in] type The type of matchpoint
//! @param[in] addr The address of the matchpoint
 
//! @return The entry found, or NULL if the entry was not found
MpEntry *
MpHash::lookup (MpType type,
uint32_t addr)
{
int hv = addr % size;
 
// Search
for (MpEntry *curr = hashTab[hv]; NULL != curr; curr = curr->next)
{
if ((type == curr->type) && (addr == curr->addr))
{
return curr; // The entry found
}
}
 
return NULL; // Not found
} // lookup ()
 
 
//! Delete an entry from the matchpoint hash table
 
//! If it is there the entry is deleted from the hash table. If it is not
//! there, no action is taken. The match must be on type AND addr. The entry
//! (MpEntry::) is itself deleted
 
//! The usual fun and games tracking the previous entry, so we can delete
//! things.
 
//! @param[in] type The type of matchpoint
//! @param[in] addr The address of the matchpoint
//! @param[out] instr Location to place the instruction found. If NULL (the
//! default) then the instruction is not written back.
 
//! @return TRUE if an entry was found and deleted
bool
MpHash::remove (MpType type,
uint32_t addr,
uint32_t *instr)
{
int hv = addr % size;
MpEntry *prev = NULL;
MpEntry *curr;
 
// Search
for (curr = hashTab[hv]; NULL != curr; curr = curr->next)
{
if ((type == curr->type) && (addr == curr->addr))
{
// Found - delete. Method depends on whether we are the head of
// chain.
if (NULL == prev)
{
hashTab[hv] = curr->next;
}
else
{
prev->next = curr->next;
}
 
if (NULL != instr)
{
*instr = curr->instr; // Return the found instruction
}
 
delete curr;
return true; // Success
}
 
prev = curr;
}
 
return false; // Not found
 
} // remove ()
/src/Or1200MonitorSC.cpp
37,6 → 37,8
#include "Or1200MonitorSC.h"
#include "OrpsocMain.h"
 
#include <errno.h>
int monitor_to_gdb_pipe[2][2]; // [0][] - monitor to gdb, [1][] - gdb to monitor, [][0] - read, [][1] - write
 
SC_HAS_PROCESS( Or1200MonitorSC );
 
54,25 → 56,34
accessor (_accessor),
memoryload(_memoryload)
{
 
// If not -log option, then don't log
string logfileDefault("vlt-executed.log");
string logfileDefault(DEFAULT_EXEC_LOG_FILE);
string logfileNameString;
profiling_enabled = 0;
logging_enabled = false;
logfile_name_provided = false;
profiling_enabled = false;
string profileFileName(DEFAULT_PROF_FILE);
memdumpFileName = (DEFAULT_MEMDUMP_FILE);
int memdump_start = 0; int memdump_end = 0;
do_memdump = 0; // Default is not to do a dump of RAM at finish
do_memdump = false; // Default is not to do a dump of RAM at finish
logging_regs = true; // Execution log includes register values by default
bool rsp_server_enabled = false;
wait_for_stall_cmd_response = false; // Default
insn_count = insn_count_rst = 0;
cycle_count = cycle_count_rst = 0;
 
insn_count=0;
cycle_count=0;
exit_perf_summary_enabled = true; // Simulation exit performance summary is
// on by default. Turn off with "-q" on the
// cmd line
monitor_for_crash = false;
lookslikewevecrashed_count = crash_monitor_buffer_head = 0;
 
exit_perf_summary_enabled = 1; // Simulation exit performance summary is
// on by default. Turn off with "-q" on the cmd line
bus_trans_log_enabled = bus_trans_log_name_provided =
bus_trans_log_start_delay_enable = false; // Default
string bus_trans_default_log_name(DEFAULT_BUS_LOG_FILE);
string bus_trans_log_file;
 
// Parse the command line options
int cmdline_name_found=0;
bool cmdline_name_found = false;
if (argc > 1)
{
// Search through the command line parameters for the "-log" option
81,30 → 92,70
if ((strcmp(argv[i], "-l")==0) ||
(strcmp(argv[i], "--log")==0))
{
logfileNameString = (argv[i+1]);
cmdline_name_found=1;
logging_enabled = true;
binary_log_format = false;
if (i+1 < argc)
if(argv[i+1][0] != '-')
{
logfileNameString = (argv[i+1]);
logfile_name_provided = true;
}
if (!logfile_name_provided)
logfileNameString = logfileDefault;
}
else if ((strcmp(argv[i], "--log-noregs")==0))
{
logging_regs = false;
}
else if ((strcmp(argv[i], "-b")==0) ||
(strcmp(argv[i], "--binlog")==0))
{
logging_enabled = true;
binary_log_format = true;
if (i+1 < argc)
if(argv[i+1][0] != '-')
{
logfileNameString = (argv[i+1]);
logfile_name_provided = true;
}
if (!logfile_name_provided)
logfileNameString = logfileDefault;
 
}
else if ((strcmp(argv[i], "-c")==0) ||
(strcmp(argv[i], "--crash-monitor")==0))
{
monitor_for_crash = true;
}
else if ((strcmp(argv[i], "-q")==0) ||
(strcmp(argv[i], "--quiet")==0))
{
exit_perf_summary_enabled = 0;
exit_perf_summary_enabled = false;
}
else if ((strcmp(argv[i], "-p")==0) ||
(strcmp(argv[i], "--profile")==0))
{
profiling_enabled = 1;
// Check for !end of command line and that next thing is not a command
profiling_enabled = true;
// Check for !end of command line and that next thing is not a
// command
if ((i+1 < argc)){
if(argv[i+1][0] != '-')
profileFileName = (argv[i+1]);
}
}
else if ( (strcmp(argv[i], "-r")==0) ||
(strcmp(argv[i], "--rsp")==0) )
{
// We need to detect this here too
rsp_server_enabled = true;
}
else if ((strcmp(argv[i], "-m")==0) ||
(strcmp(argv[i], "--memdump")==0))
{
do_memdump = 1;
// Check for !end of command line and that next thing is not a command
// or a memory address
do_memdump = true;
// Check for !end of command line and that next thing is not a
// command or a memory address
if (i+1 < argc)
{
if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) != 0))
137,10 → 188,41
}
}
}
else if ((strcmp(argv[i], "-u")==0) ||
(strcmp(argv[i], "--bus-log")==0))
{
bus_trans_log_enabled = true;
if (i+1 < argc)
if(argv[i+1][0] != '-')
{
bus_trans_log_file = (argv[i+1]);
bus_trans_log_name_provided = true;
}
if (!bus_trans_log_name_provided)
bus_trans_log_file = bus_trans_default_log_name;
// check for a log start delay
if (i+2 < argc)
if(argv[i+2][0] != '-')
{
// We have a bus transaction log start delay
bus_trans_log_start_delay_enable = true;
int time_val = atoi(argv[i+2]);
sc_time log_start_time(time_val,SC_NS);
bus_trans_log_start_delay = log_start_time;
}
}
}
}
 
if (!rsp_server_enabled)
{
monitor_to_gdb_pipe[0][0] = monitor_to_gdb_pipe[0][1] = NULL;
monitor_to_gdb_pipe[1][0] = monitor_to_gdb_pipe[1][1] = NULL;
}
 
// checkInstruction monitors the bus for special NOP instructionsl
SC_METHOD (checkInstruction);
150,11 → 232,12
if (profiling_enabled)
{
profileFile.open(profileFileName.c_str(), ios::out); // Open profiling log file
if(profileFile.is_open())
{
// If the file was opened OK, then enabled logging and print a message.
profiling_enabled = 1;
profiling_enabled = true;
cout << "* Execution profiling enabled. Logging to " << profileFileName << endl;
}
165,29 → 248,52
start = clock();
}
 
if(cmdline_name_found==1) // No -log option specified so don't turn on logging
if(logging_enabled)
{
 
logging_enabled = 0; // Default is logging disabled
statusFile.open(logfileNameString.c_str(), ios::out ); // open file to write to it
 
if(statusFile.is_open())
/* Now open the file */
if (binary_log_format)
statusFile.open(logfileNameString.c_str(), ios::out | ios::binary);
else
statusFile.open(logfileNameString.c_str(), ios::out );
/* Check the open() */
if(statusFile.is_open() && binary_log_format)
{
// If we could open the file then turn on logging
logging_enabled = 1;
cout << "* Processor execution logged to file: " << logfileNameString << endl;
cout << "* Processor execution logged in binary format to file: " << logfileNameString << endl;
/* Write out a byte indicating whether there's register values too */
statusFile.write((char*)&logging_regs, 1);
}
else if (statusFile.is_open() && !binary_log_format)
cout << "* Processor execution logged to file: " << logfileNameString << endl;
else
/* Couldn't open */
logging_enabled = false;
}
if (logging_enabled)
{
SC_METHOD (displayState);
{
if (binary_log_format)
{
SC_METHOD (displayStateBinary);
}
else
{
SC_METHOD (displayState);
}
sensitive << clk.pos();
dont_initialize();
start = clock();
}
 
if (monitor_for_crash)
{
cout << "* Crash monitor enabled" << endl;
}
 
// Check sizes we were given from memory dump command line options first
if (do_memdump)
{
194,7 → 300,7
if ((memdump_start > ORPSOC_SRAM_SIZE) || (memdump_end > ORPSOC_SRAM_SIZE) ||
((memdump_start > memdump_end) && (memdump_end != 0)))
{
do_memdump = 0;
do_memdump = false;
cout << "* Memory dump addresses range incorrect. Limit of memory is 0x" << hex << ORPSOC_SRAM_SIZE << ". Memory dumping disabled." << endl;
}
}
221,25 → 327,53
memdump_start_addr = memdump_start;
memdump_end_addr = memdump_end;
}
}
 
if (bus_trans_log_enabled)
{
// Setup log file and register the bus monitoring function
busTransLog.open(bus_trans_log_file.c_str(), ios::out );
 
if (busTransLog.is_open())
{
cout << "* System bus transactions logged to file: " <<
bus_trans_log_file;
if (bus_trans_log_start_delay_enable)
cout << ", on at " << bus_trans_log_start_delay.to_string();
cout << endl;
}
else
/* Couldn't open */
bus_trans_log_enabled = false;
}
 
if (bus_trans_log_enabled)
{
// Setup profiling function
SC_METHOD (busMonitor);
sensitive << clk.pos();
dont_initialize();
}
} // Or1200MonitorSC ()
 
//! Print command line switches for the options of this module
void
Or1200MonitorSC::printSwitches()
{
printf(" [-l <file>] [-q] [-p [<file>]] [-m [<file>] [<0xstardaddr> <0xendaddr>]]");
}
 
//! Print usage for the options of this module
void
Or1200MonitorSC::printUsage()
{
printf(" -p, --profile\t\tEnable execution profiling output to file (default "DEFAULT_PROF_FILE")\n");
printf(" -l, --log\t\tLog processor execution to file\n");
printf("\nLogging and diagnostic options:\n");
printf(" -p, --profile [<file>]Enable execution profiling output to <file> (default is\n\t\t\t"DEFAULT_PROF_FILE")\n");
printf(" -l, --log <file>\tLog processor execution to <file>\n");
printf(" --log-noregs\tLog excludes register contents\n");
 
printf(" -b, --binlog <file>\tGenerate binary format execution log (faster, smaller)\n");
 
printf(" -q, --quiet\t\tDisable the performance summary at end of simulation\n");
printf(" -m, --memdump\t\tDump data from the system's RAM to a file on finish\n\n");
printf(" -m, --memdump <file> <0xstartaddr> <0xendaddr>\n\t\t\tDump data between <0xstartaddr> and <0xendaddr> from\n\t\t\tthe system's RAM to <file> in binary format on exit\n");
printf(" -c, --crash-monitor\tDetect when the processor has crashed and exit\n");
printf(" -u, --bus-log <file> <val>\n\t\t\tLog the wishbone bus transactions to <file>, opt. start\n\t\t\tafter <val> ns\n\n");
 
}
 
//! Method to handle special instrutions
261,24 → 395,29
{
uint32_t r3;
double ts;
uint32_t current_WbInsn, current_WbPC;
cycle_count++;
 
/* Check if this counts as an "executed" instruction */
if (!accessor->getWbFreeze())
if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
insn_count++;
else
// Exception version
if (accessor->getExceptFlushpipe())
{
// Cache writeback stage instruction
current_WbInsn = accessor->getWbInsn();
if ((((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
insn_count++;
else
// Exception version
if (accessor->getExceptFlushpipe())
insn_count++;
}
// Check the instruction when the freeze signal is low.
//if (!accessor->getWbFreeze())
if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
{
// Do something if we have l.nop
switch (accessor->getWbInsn())
switch (current_WbInsn)
{
case NOP_EXIT:
r3 = accessor->getGpr (3);
288,6 → 427,7
perfSummary();
if (logging_enabled) statusFile.close();
if (profiling_enabled) profileFile.close();
if (bus_trans_log_enabled) busTransLog.close();
memdump();
SIM_RUNNING=0;
sc_stop();
310,12 → 450,125
r3 = accessor->getGpr (3);
std::cout << (char)r3 << std::flush;
break;
 
case NOP_CNT_RESET:
std::cout << "****************** counters reset ******************" << endl;
std::cout << "since last reset: cycles " << cycle_count - cycle_count_rst << ", insn #" << insn_count - insn_count_rst << endl;
std::cout << "****************** counters reset ******************" << endl;
cycle_count_rst = cycle_count;
insn_count_rst = insn_count;
default:
break;
}
if (monitor_for_crash)
{
current_WbPC = accessor->getWbPC();
// Look at current instruction
if (current_WbInsn == 0x00000000)
{
// Looks like we've jumped somewhere incorrectly
lookslikewevecrashed_count++;
}
#define CRASH_MONITOR_LOG_BAD_INSNS 1
#if CRASH_MONITOR_LOG_BAD_INSNS
/* Log so-called "bad" instructions, or at least instructions we
executed, no matter if they caused us to increment
lookslikewevecrashed_count, this way we get them in our list too */
if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
{
crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
/* Circular buffer */
if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
crash_monitor_buffer_head++;
else
crash_monitor_buffer_head = 0;
}
 
#else
else if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
{
 
crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
/* Circular buffer */
if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
crash_monitor_buffer_head++;
else
crash_monitor_buffer_head = 0;
/* Reset this */
lookslikewevecrashed_count = 0;
}
#endif
if (wait_for_stall_cmd_response)
{
// We've already crashed, and we're issued a command to stall the
// processor to the system C debug unit interface, and we're
// waiting for this debug unit to send back the message that we've
// stalled.
char readChar;
int n = read(monitor_to_gdb_pipe[1][0], &readChar, sizeof(char));
if (!( ((n < 0) && (errno == EAGAIN)) || (n==0) ))
wait_for_stall_cmd_response = false; // We got response
lookslikewevecrashed_count = 0;
}
else if (lookslikewevecrashed_count > 0)
{
if (lookslikewevecrashed_count >= CRASH_MONITOR_BUFFER_SIZE/4)
{
/* Probably crashed. Bail out, print out buffer */
std::cout << "********************************************************************************"<< endl;
std::cout << "* Looks like processor crashed. Printing last " << CRASH_MONITOR_BUFFER_SIZE << " instructions executed:" << endl;
int crash_monitor_buffer_head_end = (crash_monitor_buffer_head > 0) ? crash_monitor_buffer_head - 1 : CRASH_MONITOR_BUFFER_SIZE-1;
while (crash_monitor_buffer_head != crash_monitor_buffer_head_end)
{
std::cout << "* PC: " << std::setfill('0') << hex << std::setw(8) << crash_monitor_buffer[crash_monitor_buffer_head][0] << " INSN: " << std::setfill('0') << hex << std::setw(8) << crash_monitor_buffer[crash_monitor_buffer_head][1] << endl;
if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
crash_monitor_buffer_head++;
else
crash_monitor_buffer_head = 0;
}
std::cout << "********************************************************************************"<< endl;
if ( (monitor_to_gdb_pipe[0][0] != NULL))
{
// If GDB server is running, we'll pass control back to
// the debugger instead of just quitting.
char interrupt = 0x3; // Arbitrary
write(monitor_to_gdb_pipe[0][1],&interrupt,sizeof(char));
wait_for_stall_cmd_response = true;
lookslikewevecrashed_count = 0;
std::cout << "* Stalling processor and returning control to GDB"<< endl;
// Problem: the debug unit interface's stalling the processor over the simulated JTAG bus takes a while, in the meantime this monitor will continue running and keep triggering the crash detection code. We must somehow wait until the processor is stalled, or circumvent this crash detection output until we detect that the processor is stalled.
// Solution: Added another pipe, when we want to wait for preocssor to stall, we set wait_for_stall_cmd_response=true, then each time we get back to this monitor function we simply poll the pipe until we're stalled. (A blocking read didn't work - this function never yielded and the RSP server handling function never got called).
wait_for_stall_cmd_response = true;
}
else
{
// Close down sim end exit
ts = sc_time_stamp().to_seconds() * 1000000000.0;
std::cout << std::fixed << std::setprecision (2) << ts;
std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
perfSummary();
if (logging_enabled) statusFile.close();
if (profiling_enabled) profileFile.close();
if (bus_trans_log_enabled) busTransLog.close();
memdump();
SIM_RUNNING=0;
sc_stop();
}
}
}
}
}
 
} // checkInstruction()
 
 
389,11 → 642,10
//! This copies what the verilog testbench module, or1200_monitor does in it its
//! process which calls the display_arch_state tasks. This is designed to be
//! identical to that process, so the output is identical
#define PRINT_REGS 1
 
void
Or1200MonitorSC::displayState()
{
bool printregs = false;
// Output the state if we're not frozen and not flushing during a delay slot
if (!accessor->getWbFreeze())
{
401,41 → 653,35
{
// Print PC, instruction
statusFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << insn_count << "): " << std::setfill('0') << hex << std::setw(8) << accessor->getWbPC() << ": " << hex << std::setw(8) << accessor->getWbInsn() << endl;
#if PRINT_REGS
printregs = true;
#endif
}
// Exception version
else if (accessor->getExceptFlushpipe())
{
// Print PC, instruction, indicate it caused an exception
statusFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << insn_count << "): " << std::setfill('0') << hex << std::setw(8) << accessor->getExPC() << ": " << hex << std::setw(8) << accessor->getExInsn() << " (exception)" << endl;
}
else
return;
}
else
return;
if (logging_regs)
{
// Print general purpose register contents
for (int i=0; i<32; i++)
{
// Exception version
if (accessor->getExceptFlushpipe())
{
// Print PC, instruction, indicate it caused an exception
statusFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << insn_count << "): " << std::setfill('0') << hex << std::setw(8) << accessor->getExPC() << ": " << hex << std::setw(8) << accessor->getExInsn() << " (exception)" << endl;
#if PRINT_REGS
printregs = true;
#endif
 
}
if ((i%4 == 0)&&(i>0)) statusFile << endl;
statusFile << std::setfill('0');
statusFile << "GPR" << dec << std::setw(2) << i << ": " << hex << std::setw(8) << (uint32_t) accessor->getGpr(i) << " ";
}
statusFile << endl;
if (printregs)
{
// Print general purpose register contents
for (int i=0; i<32; i++)
{
if ((i%4 == 0)&&(i>0)) statusFile << endl;
statusFile << std::setfill('0');
statusFile << "GPR" << dec << std::setw(2) << i << ": " << hex << std::setw(8) << (uint32_t) accessor->getGpr(i) << " ";
}
statusFile << endl;
statusFile << "SR : " << hex << std::setw(8) << (uint32_t) accessor->getSprSr() << " ";
statusFile << "EPCR0: " << hex << std::setw(8) << (uint32_t) accessor->getSprEpcr() << " ";
statusFile << "EEAR0: " << hex << std::setw(8) << (uint32_t) accessor->getSprEear() << " ";
statusFile << "ESR0 : " << hex << std::setw(8) << (uint32_t) accessor->getSprEsr() << endl;
statusFile << "SR : " << hex << std::setw(8) << (uint32_t) accessor->getSprSr() << " ";
statusFile << "EPCR0: " << hex << std::setw(8) << (uint32_t) accessor->getSprEpcr() << " ";
statusFile << "EEAR0: " << hex << std::setw(8) << (uint32_t) accessor->getSprEear() << " ";
statusFile << "ESR0 : " << hex << std::setw(8) << (uint32_t) accessor->getSprEsr() << endl;
}
}
return;
442,6 → 688,80
} // displayState()
 
//! Method to output the state of the processor in binary format
//! File format is simply first byte indicating whether register
//! data is included, and then structs of the following type
struct s_binary_output_buffer{
long long insn_count;
uint32_t pc;
uint32_t insn;
char exception;
uint32_t regs[32];
uint32_t sr;
uint32_t epcr0;
uint32_t eear0;
uint32_t eser0;
} __attribute__((__packed__));
 
struct s_binary_output_buffer_sans_regs{
long long insn_count;
uint32_t pc;
uint32_t insn;
char exception;
} __attribute__((__packed__));
void
Or1200MonitorSC::displayStateBinary()
{
struct s_binary_output_buffer outbuf;
// Output the state if we're not frozen and not flushing during a delay slot
if (!accessor->getWbFreeze())
{
if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
{
outbuf.insn_count = insn_count;
outbuf.pc = (uint32_t) accessor->getWbPC();
outbuf.insn = (uint32_t) accessor->getWbInsn();
outbuf.exception = 0;
}
// Exception version
else if (accessor->getExceptFlushpipe())
{
outbuf.insn_count = insn_count;
outbuf.pc = (uint32_t) accessor->getExPC();
outbuf.insn = (uint32_t) accessor->getExInsn();
outbuf.exception = 1;
}
else
return;
}
else
return;
if (logging_regs)
{
// Print general purpose register contents
for (int i=0; i<32; i++)
outbuf.regs[i] = (uint32_t) accessor->getGpr(i);
 
outbuf.sr = (uint32_t) accessor->getSprSr();
outbuf.epcr0 = (uint32_t) accessor->getSprEpcr();
outbuf.eear0 = (uint32_t) accessor->getSprEear();
outbuf.eser0 = (uint32_t) accessor->getSprEsr();
statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer));
}
else
statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer_sans_regs));
return;
} // displayStateBinary()
 
//! Function to calculate the number of instructions performed and the time taken
void
Or1200MonitorSC::perfSummary()
460,7 → 780,7
int hertz = (int) ((cycles/elapsed_time)/1000);
std::cout << "* Or1200Monitor: simulated " << sc_time_stamp() << ", time elapsed: " << elapsed_time << " seconds" << endl;
std::cout << "* Or1200Monitor: simulated " << dec << cycles << " clock cycles, executed at approx " << hertz << "kHz" << endl;
std::cout << "* Or1200Monitor: simulated " << insn_count << " instructions, insn/sec. = " << ips << ", mips = " << mips << endl;
std::cout << "* Or1200Monitor: simulated " << insn_count << " instructions, insn/sec. = " << ips /*<< ", mips = " << mips*/ << endl;
}
return;
} // perfSummary
508,3 → 828,79
memdumpFile.close();
}
 
 
void
Or1200MonitorSC::busMonitor()
{
 
// This is for the wb_conmax module. Presumably other Wishbone bus arbiters
// will need this section of the code to be re-written appropriately, along
// with the relevent functions in the OrpsocAccess module.
static busLogStates busLogState = BUS_LOG_IDLE;
static int currentMaster = -1;
static uint32_t currentAddr = 0, currentDataIn = 0;
static uint32_t currentSel = 0, currentSlave = 0;
static bool currentWe = false;
static int cyclesWaited = 0;
 
if (bus_trans_log_start_delay_enable)
{
if (sc_time_stamp() >= bus_trans_log_start_delay)
{
// No longer waiting
bus_trans_log_start_delay_enable = false;
cout << "* System log now enabled (time = " << bus_trans_log_start_delay.to_string() << ")" << endl;
}
if (bus_trans_log_start_delay_enable)
return;
}
switch ( busLogState )
{
case BUS_LOG_IDLE:
{
// Check the current granted master's cyc and stb inputs
uint32_t gnt = accessor->getWbArbGrant();
if (accessor->getWbArbMastCycI(gnt) && accessor->getWbArbMastStbI(gnt) &&
!accessor->getWbArbMastAckO(gnt))
{
currentAddr = accessor->getWbArbMastAdrI(gnt);
currentDataIn = accessor->getWbArbMastDatI(gnt);
currentSel = (uint32_t) accessor->getWbArbMastSelI(gnt);
currentSlave = (uint32_t)accessor->getWbArbMastSlaveSelDecoded(gnt)-1;
currentWe = accessor->getWbArbMastWeI(gnt);
currentMaster = gnt;
busLogState = BUS_LOG_WAIT_FOR_ACK;
cyclesWaited = 0;
}
}
break;
case BUS_LOG_WAIT_FOR_ACK:
cyclesWaited++;
// Check for ACK
if (accessor->getWbArbMastAckO(currentMaster))
{
// Transaction completed
busTransLog << sc_time_stamp() << " M" << currentMaster << " ";
if (currentWe)
busTransLog << " W " << hex << currentSel << " " << hex << std::setfill('0') << std::setw(8) << currentAddr << " S" << dec << currentSlave << " " << hex << std::setw(8) << currentDataIn << " " << dec << cyclesWaited << endl;
else
busTransLog << " R " << hex << currentSel << " " << hex << std::setfill('0') << std::setw(8) << currentAddr << " S" << dec << currentSlave << " " << hex << std::setw(8) << accessor->getWbArbMastDatO(currentMaster) << " " << dec << cyclesWaited << endl;
busLogState = BUS_LOG_IDLE;
}
break;
}
 
return;
} // busMonitor ()
/src/TapActionIRScan.cpp
0,0 → 1,178
// ----------------------------------------------------------------------------
 
// TAP IR-Scan action: implementation
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
 
#include "TapActionIRScan.h"
#include "TapStateMachine.h"
 
 
//! Constructor
 
//! Sets up the superclass with the SystemC completion event and initializes
//! our state as appropriate.
 
//! @param[in] doneEvent SystemC event to be signalled when this action is
//! complete.
//! @param[in] _iRegIn The register to shift in.
//! @param[in] _iRegSize Size in bits of the register to shift in.
 
TapActionIRScan::TapActionIRScan (sc_core::sc_event *_doneEvent,
uint32_t _iRegIn,
int _iRegSize) :
TapAction (_doneEvent),
iRegIn (_iRegIn),
iRegSize (_iRegSize),
iRegOut (0),
bitsShifted (0),
iRScanState (SHIFT_IR_PREPARING)
{
 
} // TapActionIRScan ()
 
 
//! Process the Shift-IR action
 
//! This drives the IR-Scan state. We can only do this if we have the TAP
//! state machine in a consistent state, which in turn is only possible if we
//! have been through a reset cycle.
 
//! If the state machine shows it has yet to be through a reset cycle, we
//! drive that cycle, after issuing a warning. This functionality is provided
//! by the parent class, TapAction::.
 
//! @param[in] tapStateMachine The TAP state machine with which this action
//! is associated.
//! @param[out] tdi The value to drive on TDI
//! @param[in] tdo The value currently on TDO
//! @param[out] tms The value to drive on TMS
 
//! @return True if the action is complete
 
bool
TapActionIRScan::process (TapStateMachine *tapStateMachine,
bool &tdi,
bool tdo,
bool &tms)
{
// Ensure we are in a consistent state. If not then we'll have moved towards
// it and can return with the given tms
if (!checkResetDone (tapStateMachine, tms, true))
{
return false;
}
 
// We are consistent, so work through the IR-Scan process
switch (iRScanState)
{
case SHIFT_IR_PREPARING:
 
// Are we in the Shift-IR state yet?
if (!tapStateMachine->targetState (TAP_SHIFT_IR, tms))
{
return false; // Not there. Accept the TMS value
}
else
{
iRScanState = SHIFT_IR_SHIFTING; // Drop through
}
 
case SHIFT_IR_SHIFTING:
 
// Are we still shifting stuff?
if (bitsShifted < iRegSize)
{
// We are in the Shift-IR state. Another bit about to be done, so
// increment the count
bitsShifted++;
 
// Shift out the TDI value from the bottom of the register
tdi = iRegIn & 1;
iRegIn >>= 1;
 
// Record the TDO value. This is always a cycle late, so we ignore
// it the first time. The value shifts in from the top.
if (bitsShifted > 1)
{
iRegOut >>= 1; // Move all the existing bits right
if (tdo) // OR any new bit in
{
uint32_t tmpBit = 1 << (iRegSize - 1);
iRegOut |= tmpBit;
}
}
 
// TMS is 0 to keep us here UNLESS this is the last bit, in which
// case it is 1 to move us into Exit1-IR.
tms = (bitsShifted == iRegSize);
 
return false;
}
else
{
// Capture the last TDO bit
iRegOut >>= 1; // Move all the existing bits right
 
if (tdo) // OR any new bit in
{
uint32_t tmpBit = 1 << (iRegSize - 1);
iRegOut |= tmpBit;
}
 
iRScanState = SHIFT_IR_UPDATING; // Drop through
}
 
case SHIFT_IR_UPDATING:
 
// Are we still trying to update?
if (!tapStateMachine->targetState (TAP_UPDATE_IR, tms))
{
return false; // Not there. Accept the TMS value
}
else
{
return true; // All done
}
}
} // process ()
 
 
//! Get the shifted out register
 
//! @return The value of the shifted our register
 
uint32_t
TapActionIRScan::getIRegOut ()
{
return iRegOut;
 
} // getIRegOut ()
 
 
/src/TapAction.cpp
0,0 → 1,119
// ----------------------------------------------------------------------------
 
// TAP action header: abstract class implementation
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
#include <iostream>
 
#include "TapAction.h"
 
class sc_event;
 
 
//! Constructor
 
//! Records the SystemC event used to notify completion and sets the
//! resetCounter to zero.
 
//! @param _actionType The action type
 
TapAction::TapAction (sc_core::sc_event *_doneEvent) :
doneEvent (_doneEvent),
resetCounter (0)
{
 
} // TapAction ()
 
 
//! Accessor to get the SystemC completion event
 
//! @return The SystemC completion event
 
sc_core::sc_event *
TapAction::getDoneEvent ()
{
return doneEvent;
 
} // getDoneEvent ()
 
 
//! Function to check the TAP is in a consistent state, optionally with a
//! warning.
 
//! This is a convenience for subclasses (hence protected), so they can ensure
//! the state machine is in a consistent state.
 
//! @note The method returns TRUE to indicate that the machine is in the
//! consistent state. However the TapStateMachine resetDone flag is set
//! when the final TMS is set - the state will only be reached IF that
//! TMS is driven. This mechanism gives users flexibility. They can
//! detect the final TMS being driven.
 
//! @param[in] tapStateMachine The TAP state machine with which we are
//! associated.
//! @param[out] tms The value to drive on the JTAG TMS
//! @param[in] warn True to indicate a warning message should be
//! issued when starting a reset cycle.
 
//! @return TRUE if the TAP state machine was already in a consistent state.
 
bool
TapAction::checkResetDone (TapStateMachine *tapStateMachine,
bool &tms,
bool warn)
{
// Nothing more to do if we are consistent
if (tapStateMachine->getResetDone ())
{
return true;
}
 
// Need to reset. If requested and this is the first cycle of reset, give a
// warning.
if (warn && (0 == resetCounter))
{
std::cerr << "JTAG TAP state inconsistent: resetting" << std::endl;
}
 
// Drive towards reset
resetCounter++;
tms = 1;
 
// If we have got to the end of the reset sequence we can clear the
// tapStateMachine and report we are consistent. However we will not return
// true until the next call.
if (tapStateMachine->TAP_RESET_CYCLES == resetCounter)
{
tapStateMachine->setResetDone (true);
resetCounter = 0; // Ready for next time
}
else
{
return false;
}
} // checkResetDone ()
/src/RspConnection.cpp
0,0 → 1,673
// ----------------------------------------------------------------------------
 
// Remote Serial Protocol connection: implementation
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: RspConnection.cpp 327 2009-03-07 19:10:56Z jeremy $
 
#include <iostream>
#include <iomanip>
 
#include <cerrno>
#include <csignal>
#include <cstring>
 
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <poll.h>
 
#include "RspConnection.h"
#include "Utils.h"
 
using std::cerr;
using std::cout;
using std::dec;
using std::endl;
using std::flush;
using std::hex;
using std::setfill;
using std::setw;
 
// Define RSP_TRACE to turn on tracing of packets sent and received
// #define RSP_TRACE
 
 
//-----------------------------------------------------------------------------
//! Constructor when using a port number
 
//! Calls the generic initializer.
 
//! @param[in] _portNum The port number to connect to
//-----------------------------------------------------------------------------
RspConnection::RspConnection (int _portNum)
{
rspInit (_portNum, DEFAULT_RSP_SERVICE);
 
} // RspConnection ()
 
 
//-----------------------------------------------------------------------------
//! Constructor when using a service
 
//! Calls the generic initializer.
 
//! @param[in] _serviceName The service name to use. Defaults to
//! DEFAULT_RSP_SERVER
//-----------------------------------------------------------------------------
RspConnection::RspConnection (const char *_serviceName)
{
rspInit (0, _serviceName);
 
} // RspConnection ()
 
 
//-----------------------------------------------------------------------------
//! Destructor
 
//! Close the connection if it is still open
//-----------------------------------------------------------------------------
RspConnection::~RspConnection ()
{
this->rspClose (); // Don't confuse with any other close ()
 
} // ~RspConnection ()
 
 
//-----------------------------------------------------------------------------
//! Generic initialization routine specifying both port number and service
//! name.
 
//! Private, since this is not intended to be called by users. The service
//! name is only used if port number is zero.
 
//! Allocate the two fifos from packets from the client and to the client.
 
//! We only use a single packet in transit at any one time, so allocate that
//! packet here (rather than getting a new one each time.
 
//! @param[in] _portNum The port number to connect to
//! @param[in] _serviceName The service name to use (if PortNum == 0).
//-----------------------------------------------------------------------------
void
RspConnection::rspInit (int _portNum,
const char *_serviceName)
{
portNum = _portNum;
serviceName = _serviceName;
clientFd = -1;
 
} // init ()
 
 
//-----------------------------------------------------------------------------
//! Get a new client connection.
 
//! Blocks until the client connection is available.
 
//! A lot of this code is copied from remote_open in gdbserver remote-utils.c.
 
//! This involves setting up a socket to listen on a socket for attempted
//! connections from a single GDB instance (we couldn't be talking to multiple
//! GDBs at once!).
 
//! The service is specified either as a port number in the Or1ksim
//! configuration (parameter rsp_port in section debug, default 51000) or as a
//! service name in the constant OR1KSIM_RSP_SERVICE.
 
//! If there is a catastrophic communication failure, service will be
//! terminated using sc_stop.
 
//! The protocol used for communication is specified in OR1KSIM_RSP_PROTOCOL.
 
//! @return TRUE if the connection was established or can be retried. FALSE
//! if the error was so serious the program must be aborted.
//-----------------------------------------------------------------------------
bool
RspConnection::rspConnect ()
{
// 0 is used as the RSP port number to indicate that we should use the
// service name instead.
if (0 == portNum)
{
struct servent *service = getservbyname (serviceName, "tcp");
 
if (NULL == service)
{
cerr << "ERROR: RSP unable to find service \"" << serviceName
<< "\": " << strerror (errno) << endl;
return false;
}
 
portNum = ntohs (service->s_port);
}
 
// Open a socket on which we'll listen for clients
int tmpFd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (tmpFd < 0)
{
cerr << "ERROR: Cannot open RSP socket" << endl;
return false;
}
 
// Allow rapid reuse of the port on this socket
int optval = 1;
setsockopt (tmpFd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval,
sizeof (optval));
 
 
 
// Bind the port to the socket
struct sockaddr_in sockAddr;
sockAddr.sin_family = PF_INET;
sockAddr.sin_port = htons (portNum);
sockAddr.sin_addr.s_addr = INADDR_ANY;
 
if (bind (tmpFd, (struct sockaddr *) &sockAddr, sizeof (sockAddr)))
{
cerr << "ERROR: Cannot bind to RSP socket" << endl;
return false;
}
// Listen for (at most one) client
if (listen (tmpFd, 1))
{
cerr << "ERROR: Cannot listen on RSP socket" << endl;
return false;
}
cout << "Listening for RSP on port " << portNum << endl << flush;
 
// Accept a client which connects
socklen_t len; // Size of the socket address
clientFd = accept (tmpFd, (struct sockaddr *)&sockAddr, &len);
 
if (-1 == clientFd)
{
cerr << "Warning: Failed to accept RSP client" << endl;
return true; // OK to retry
}
 
// Enable TCP keep alive process
optval = 1;
setsockopt (clientFd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval,
sizeof (optval));
 
int flags;
/* If they have O_NONBLOCK, use the Posix way to do it */
#if defined(O_NONBLOCK)
/* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
if (-1 == (flags = fcntl(clientFd, F_GETFL, 0)))
flags = 0;
fcntl(clientFd, F_SETFL, flags | O_NONBLOCK);
#else
/* Otherwise, use the old way of doing it */
flags = 1;
ioctl(clientFd, FIOBIO, &flags);
#endif
 
/* Set socket to be non-blocking */
 
/* We do this because when we're given a continue, or step
instruction,command we set the processor stall off, then instantly check
if it's stopped. If it hasn't then we drop through and wait for input
from GDB. Obviously this will cause problems when it will stop after we
do the check. So now, rspSocketPeek() been implemented to simply check if
there's an incoming command from GDB (although, mainly interested in
int. commands), otherwise it returns back to poll the processor's
stall bit. It can only do this if the socket is non-blocking.
 
At first test, simply adding this line appeared to give no problems with
the existing code. No "simulation" of blocking behaviour on the
non-blocking socket was required (in the event that a read/write throws
back a EWOULDBLOCK error, as was looked to be the case in the previous
GDB handling code) -- Julius
*/
if (ioctl(clientFd, FIONBIO, (char *)&optval) > 0 )
{
cerr << "RspConnect: ioctl failed, line "<< __LINE__ << endl;
close(clientFd);
close(tmpFd);
return false;
}
 
// Don't delay small packets, for better interactive response (disable
// Nagel's algorithm)
optval = 1;
setsockopt (clientFd, IPPROTO_TCP, TCP_NODELAY, (char *)&optval,
sizeof (optval));
 
// Socket is no longer needed
close (tmpFd); // No longer need this
signal (SIGPIPE, SIG_IGN); // So we don't exit if client dies
 
cout << "Remote debugging from host " << inet_ntoa (sockAddr.sin_addr)
<< endl;
return true;
 
} // rspConnect ()
 
 
//-----------------------------------------------------------------------------
//! Close a client connection if it is open
//-----------------------------------------------------------------------------
void
RspConnection::rspClose ()
{
if (isConnected ())
{
cout << "Closing connection" << endl;
close (clientFd);
clientFd = -1;
}
} // rspClose ()
 
 
//-----------------------------------------------------------------------------
//! Report if we are connected to a client.
 
//! @return TRUE if we are connected, FALSE otherwise
//-----------------------------------------------------------------------------
bool
RspConnection::isConnected ()
{
return -1 != clientFd;
 
} // isConnected ()
 
//-----------------------------------------------------------------------------
//! Peek at data coming into server from GDB
//! Useful for polling for ETX (0x3) chars being sent when GDB wants to
//! interrupt
//! @return the char we peeked, 0 otherwise
//-----------------------------------------------------------------------------
char
RspConnection::rspSocketPeek()
{
char c;
int n;
// Using recv here instead of read becuase we can pass the MSG_PEEK
// flag, which lets us look at what's on the socket, without actually
// taking it off
 
//if (DEBUG_GDB)
// printf("peeking at GDB socket...\n");
n = recv (clientFd, &c, sizeof (c), MSG_PEEK);
//if (DEBUG_GDB)
// printf("peeked, got n=%d, c=0x%x\n",n, c);
if (n>0)
return c;
else
return -1;
/*
if (n > 0)
return c;
else
return '\0';
*/
 
}
 
//-----------------------------------------------------------------------------
//! Get the next packet from the RSP connection
 
//! Modeled on the stub version supplied with GDB. This allows the user to
//! replace the character read function, which is why we get stuff a character
//! at at time.
 
//! Unlike the reference implementation, we don't deal with sequence
//! numbers. GDB has never used them, and this implementation is only intended
//! for use with GDB 6.8 or later. Sequence numbers were removed from the RSP
//! standard at GDB 5.0.
 
//! Since this is SystemC, if we hit something that is not a packet and
//! requires a restart/retransmission, we wait so another thread gets a lookin.
 
//! @param[in] pkt The packet for storing the result.
 
//! @return TRUE to indicate success, FALSE otherwise (means a communications
//! failure)
//-----------------------------------------------------------------------------
bool
RspConnection::getPkt (RspPacket *pkt)
{
// Keep getting packets, until one is found with a valid checksum
while (true)
{
int bufSize = pkt->getBufSize ();
unsigned char checksum; // The checksum we have computed
int count; // Index into the buffer
int ch; // Current character
 
 
// Wait around for the start character ('$'). Ignore all other
// characters
ch = getRspChar ();
while (ch != '$')
{
if (-1 == ch)
{
return false; // Connection failed
}
else
{
ch = getRspChar ();
}
}
 
// Read until a '#' or end of buffer is found
checksum = 0;
count = 0;
while (count < bufSize - 1)
{
ch = getRspChar ();
 
if (-1 == ch)
{
return false; // Connection failed
}
 
// If we hit a start of line char begin all over again
if ('$' == ch)
{
checksum = 0;
count = 0;
 
continue;
}
 
// Break out if we get the end of line char
if ('#' == ch)
{
break;
}
 
// Update the checksum and add the char to the buffer
checksum = checksum + (unsigned char)ch;
pkt->data[count] = (char)ch;
count++;
}
 
// Mark the end of the buffer with EOS - it's convenient for non-binary
// data to be valid strings.
pkt->data[count] = 0;
pkt->setLen (count);
 
// If we have a valid end of packet char, validate the checksum. If we
// don't it's because we ran out of buffer in the previous loop.
if ('#' == ch)
{
unsigned char xmitcsum; // The checksum in the packet
 
ch = getRspChar ();
if (-1 == ch)
{
return false; // Connection failed
}
xmitcsum = Utils::char2Hex (ch) << 4;
 
ch = getRspChar ();
if (-1 == ch)
{
return false; // Connection failed
}
 
xmitcsum += Utils::char2Hex (ch);
 
// If the checksums don't match print a warning, and put the
// negative ack back to the client. Otherwise put a positive ack.
if (checksum != xmitcsum)
{
cerr << "Warning: Bad RSP checksum: Computed 0x"
<< setw (2) << setfill ('0') << hex
<< checksum << ", received 0x" << xmitcsum
<< setfill (' ') << dec << endl;
if (!putRspChar ('-')) // Failed checksum
{
return false; // Comms failure
}
}
else
{
if (!putRspChar ('+')) // successful transfer
{
return false; // Comms failure
}
else
{
#ifdef RSP_TRACE
cout << "getPkt: " << *pkt << endl;
#endif
return true; // Success
}
}
}
else
{
cerr << "Warning: RSP packet overran buffer" << endl;
}
}
 
} // getPkt ()
 
 
//-----------------------------------------------------------------------------
//! Put the packet out on the RSP connection
 
//! Modeled on the stub version supplied with GDB. Put out the data preceded
//! by a '$', followed by a '#' and a one byte checksum. '$', '#', '*' and '}'
//! are escaped by preceding them with '}' and then XORing the character with
//! 0x20.
 
//! Since this is SystemC, if we hit something that requires a
//! restart/retransmission, we wait so another thread gets a lookin.
 
//! @param[in] pkt The Packet to transmit
 
//! @return TRUE to indicate success, FALSE otherwise (means a communications
//! failure).
//-----------------------------------------------------------------------------
bool
RspConnection::putPkt (RspPacket *pkt)
{
int len = pkt->getLen ();
int ch; // Ack char
 
// Construct $<packet info>#<checksum>. Repeat until the GDB client
// acknowledges satisfactory receipt.
do
{
unsigned char checksum = 0; // Computed checksum
int count = 0; // Index into the buffer
 
if (!putRspChar ('$')) // Start char
{
return false; // Comms failure
}
 
 
// Body of the packet
for (count = 0; count < len; count++)
{
unsigned char ch = pkt->data[count];
 
// Check for escaped chars
if (('$' == ch) || ('#' == ch) || ('*' == ch) || ('}' == ch))
{
ch ^= 0x20;
checksum += (unsigned char)'}';
if (!putRspChar ('}'))
{
return false; // Comms failure
}
 
}
 
checksum += ch;
if (!putRspChar (ch))
{
return false; // Comms failure
}
}
 
if (!putRspChar ('#')) // End char
{
return false; // Comms failure
}
 
// Computed checksum
if (!putRspChar (Utils::hex2Char (checksum >> 4)))
{
return false; // Comms failure
}
if (!putRspChar (Utils::hex2Char (checksum % 16)))
{
return false; // Comms failure
}
 
// Check for ack of connection failure
ch = getRspChar ();
if (-1 == ch)
{
return false; // Comms failure
}
}
while ('+' != ch);
 
#ifdef RSP_TRACE
cout << "putPkt: " << *pkt << endl;
#endif
return true;
 
} // putPkt ()
 
 
//-----------------------------------------------------------------------------
//! Put a single character out on the RSP connection
 
//! Utility routine. This should only be called if the client is open, but we
//! check for safety.
 
//! @param[in] c The character to put out
 
//! @return TRUE if char sent OK, FALSE if not (communications failure)
//-----------------------------------------------------------------------------
bool
RspConnection::putRspChar (char c)
{
if (-1 == clientFd)
{
cerr << "Warning: Attempt to write '" << c
<< "' to unopened RSP client: Ignored" << endl;
return false;
}
 
// Write until successful (we retry after interrupts) or catastrophic
// failure.
while (true)
{
switch (write (clientFd, &c, sizeof (c)))
{
case -1:
// Error: only allow interrupts or would block
if ((EAGAIN != errno) && (EINTR != errno))
{
cerr << "Warning: Failed to write to RSP client: "
<< "Closing client connection: "
<< strerror (errno) << endl;
return false;
}
break;
 
case 0:
break; // Nothing written! Try again
 
default:
return true; // Success, we can return
}
}
} // putRspChar ()
 
 
//-----------------------------------------------------------------------------
//! Get a single character from the RSP connection
 
//! Utility routine. This should only be called if the client is open, but we
//! check for safety.
 
//! @return The character received or -1 on failure
//-----------------------------------------------------------------------------
int
RspConnection::getRspChar ()
{
if (-1 == clientFd)
{
cerr << "Warning: Attempt to read from "
<< "unopened RSP client: Ignored" << endl;
return -1;
}
 
// Blocking read until successful (we retry after interrupts) or
// catastrophic failure.
while (true)
{
unsigned char c;
 
switch (read (clientFd, &c, sizeof (c)))
{
case -1:
if (errno == EAGAIN || errno == EWOULDBLOCK)
continue;
// Error: only allow interrupts
if (EINTR != errno)
{
cerr << "Warning: Failed to read from RSP client: "
<< "Closing client connection: "
<< strerror (errno) << endl;
return -1;
}
break;
 
case 0:
return -1;
 
default:
return c & 0xff; // Success, we can return (no sign extend!)
}
}
 
} // getRspChar ()
/src/TapActionReset.cpp
0,0 → 1,89
// ----------------------------------------------------------------------------
 
// TAP reset action : implementation
 
// Copyright (C) 2009 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the Embecosm cycle accurate SystemC JTAG library.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// The C/C++ parts of this program are commented throughout in a fashion
// suitable for processing with Doxygen.
 
// ----------------------------------------------------------------------------
 
// $Id$
 
 
#include "TapActionReset.h"
 
 
//! Constructor
 
//! Records the SystemC completion event with the parent. Sets the ::firstTime
//! flag, so the ::process () method will mark the tapStateMachine as not
//! reset.
 
//! @param[in] _doneEvent The SystemC completion event
 
TapActionReset::TapActionReset (sc_core::sc_event *_doneEvent) :
TapAction (_doneEvent),
firstTime (true)
{
 
} // TapActionReset ()
 
 
//! Process the reset action
 
//! This reuses the parent class ::checkResetDone() method. The first time we
//! are called, we mark the state machine as being in an inconsistent state,
//! to force the reset.
 
//! We use the value of the TAP state machine's resetDone flag to trigger
//! completion, since this is set on the final reset cycle. The result from
//! ::checkResetDone () is only true on the first cycle AFTER reset.
 
//! @see TapAction::
 
//! @param[in] tapStateMachine The TAP state machine with which this action
//! is associated.
//! @param[out] tdi The value to drive on TDI
//! @param[in] tdo The value currently on TDO
//! @param[out] tms The value to drive on TMS
 
//! @return True if the action is complete
 
bool
TapActionReset::process (TapStateMachine *tapStateMachine,
bool &tdi,
bool tdo,
bool &tms)
{
if (firstTime)
{
tapStateMachine->setResetDone (false);
firstTime = false;
}
 
// Parent does the work (no warning message). Our result draws on the value
// set in the tapStateMachine, to avoid an extra cycle.
checkResetDone (tapStateMachine, tms, false);
 
return tapStateMachine->getResetDone ();
 
} // process ()
/src/JtagDriverSC.cpp
0,0 → 1,614
// ----------------------------------------------------------------------------
 
// SystemC JTAG driver
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: JtagDriverSC.cpp 317 2009-02-22 19:52:12Z jeremy $
 
#include <iostream>
#include <iomanip>
 
#include "JtagDriverSC.h"
 
 
SC_HAS_PROCESS (JtagDriverSC);
 
//! Constructor for the JTAG driver.
 
//! We create a SC_THREAD in which we can spit out some actions. Must be a
//! thread, since we need to wait for the actions to complete.
 
//! @param[in] name Name of this module, passed to the parent
//! constructor.
//! @param[in] _tapActionQueue Pointer to fifo of actions to perform
 
JtagDriverSC::JtagDriverSC (sc_core::sc_module_name name,
sc_core::sc_fifo<TapAction *> *_tapActionQueue) :
sc_module (name),
tapActionQueue (_tapActionQueue),
currentScanChain (OR1K_SC_UNDEF)
{
SC_THREAD (queueActions);
 
} // JtagDriverSC ()
 
 
//! SystemC thread to queue some actions
 
//! Have to use a thread, since we will end up waiting for actions to
//! complete.
 
void
JtagDriverSC::queueActions ()
{
uint32_t res; // General result variable
 
// Reset the JTAG
reset ();
 
// Select the register scan chain to stall the processor, stall the
// processor and check it has stalled
selectChain (OR1K_SC_REGISTER);
writeReg (OR1K_RSC_RISCOP, RISCOP_STALL);
 
do
{
res = readReg (OR1K_RSC_RISCOP);
std::cout << sc_core::sc_time_stamp ().to_seconds () * 1000000
<< "us: RISCOP = " << std::hex << res << std::endl;
}
while ((res & RISCOP_STALL) != RISCOP_STALL);
 
// Write the NPC SPR. Select the RISC_DEBUG scan chain, read the
// register, write the register and read it back.
selectChain (OR1K_SC_RISC_DEBUG);
 
res = readReg (0x10); // NPC
std::cout << sc_core::sc_time_stamp ().to_seconds () * 1000000
<< "us: Old NPC = " << std::hex << res << std::endl;
 
writeReg (0x10, 0x4000100);
 
res = readReg (0x10); // NPC
std::cout << sc_core::sc_time_stamp ().to_seconds () * 1000000
<< "us: New NPC = " << std::hex << res << std::endl;
 
// Unstall and check it has unstalled
selectChain (OR1K_SC_REGISTER);
writeReg (OR1K_RSC_RISCOP, 0);
 
do
{
res = readReg (OR1K_RSC_RISCOP);
std::cout << sc_core::sc_time_stamp ().to_seconds () * 1000000
<< "us: RISCOP = " << std::hex << res << std::endl;
}
while ((res & RISCOP_STALL) == RISCOP_STALL);
 
} // queueActions ()
 
 
//! Reset the JTAG
 
//! @note Must be called from a SystemC thread, because of the use of wait()
 
void
JtagDriverSC::reset ()
{
sc_core::sc_event *actionDone = new sc_core::sc_event();
TapActionReset *resetAction;
 
// Create and queue the reset action and wait for it to complete
resetAction = new TapActionReset (actionDone);
tapActionQueue->write (resetAction);
wait (*actionDone);
 
delete resetAction;
delete actionDone;
 
} // reset ()
 
 
//! Select an OpenRISC 1000 scan chain
 
//! Built on top of the JTAG commands to shift registers
//! We only do something if the scan chain needs to be changed.
//! - Shift-IR the CHAIN_SELECT instruction
//! - Shift-DR the specified chain
//! - Shift-IR the DEBUG instruction
 
//! @note Must be called from a SystemC thread, because of the use of wait()
 
//! @param[in] chain The desired scan chain
 
 
void
JtagDriverSC::selectChain (int chain)
{
if (chain == currentScanChain)
{
return;
}
else
{
currentScanChain = chain;
}
 
sc_core::sc_event *actionDone = new sc_core::sc_event();
TapActionIRScan *iRScan;
TapActionDRScan *dRScan;
 
// Create and queue the IR-Scan action for CHAIN_SELECT (no CRC)
iRScan = new TapActionIRScan (actionDone, CHAIN_SELECT_IR, JTAG_IR_LEN);
tapActionQueue->write (iRScan);
wait (*actionDone);
 
delete iRScan;
 
// Create and queue the DR-Scan action for the specified chain (which we
// know will fit into 64 bits)
uint64_t chainReg = crc8 (chain, CHAIN_DR_LEN) << (CHAIN_DR_LEN) | chain;
dRScan = new TapActionDRScan (actionDone, chainReg, CHAIN_DR_LEN + CRC_LEN);
tapActionQueue->write (dRScan);
wait (*actionDone);
 
delete dRScan;
 
// Create and queue the IR-Scan action for DEBUG (no CRC)
iRScan = new TapActionIRScan (actionDone, DEBUG_IR, JTAG_IR_LEN);
tapActionQueue->write (iRScan);
wait (*actionDone);
 
delete iRScan;
delete actionDone;
 
} // selectChain()
 
//! Read an OpenRISC 1000 JTAG register
 
//! Built on top of the JTAG commands to shift registers
//! - Shift-DR the specified address with R/W field unset
//! - read out the data shifted out.
 
//! DR register fields depend on the scan chain in use. For SC_REGISTER:
//! - [4:0] Address to read from
//! - [5] 0 indicating read
//! - [37:6] Unused
//! - [45:38] CRC (CRC-8-ATM)
 
//! For SC_RISC_DEBUG (i.e. SPRs) and SC_WISHBONE:
//! - [31:0] Address to read from
//! - [32] 0 indicating read
//! - [64:33] unused
//! - [72:65] CRC (CRC-8-ATM)
 
//! In general two Scan-DR loops are needed. The first will cause the value
//! associated with the address to be loaded into the shift register, the
//! second will actually shift that value out. So we use a subsidiary call to
//! do the read (::readReg1()). This allows a future extension, where a block
//! of registers are read efficiently by overlapping ScanDR actions.
 
//! We can also provide a variant of ::readReg1 () that is optimized for
//! "small" value.
 
//! @note Must be called from a SystemC thread, because of the use of wait()
 
//! @param[in] addr The address of the register
 
//! @return The register value read
 
uint32_t
JtagDriverSC::readReg (uint32_t addr)
{
bool firstTime = true;
int bitSizeNoCrc; // Size of reg w/o its CRC field
// Determine the size of register to read.
switch (currentScanChain)
{
case OR1K_SC_RISC_DEBUG:
bitSizeNoCrc = RISC_DEBUG_DR_LEN;
break;
case OR1K_SC_REGISTER:
bitSizeNoCrc = REGISTER_DR_LEN;
break;
case OR1K_SC_WISHBONE:
bitSizeNoCrc = WISHBONE_DR_LEN;
break;
}
 
// Read the register twice. Use an optimized version if the register is
// "small".
if ((bitSizeNoCrc + CRC_LEN) < 64)
{
(void)readReg1 (addr, bitSizeNoCrc);
return readReg1 (addr, bitSizeNoCrc);
}
else
{
uint64_t *dReg = new uint64_t [(bitSizeNoCrc + CRC_LEN + 63) / 64];
(void)readReg1 (dReg, addr, bitSizeNoCrc);
uint32_t res = readReg1 (dReg, addr, bitSizeNoCrc);
delete [] dReg;
 
return res;
}
} // readReg ()
 
 
//! Single read of an OpenRISC 1000 JTAG register
 
//! Built on top of the JTAG commands to shift registers
//! - Shift-DR the specified address with R/W field unset
//! - read out the data shifted out.
 
//! This version is for "small" values represented as a uint64_t.
 
//! @note Must be called from a SystemC thread, because of the use of wait()
 
//! @param[in] addr The address to read
//! @param[in] bitSizeNoCrc Size of the register excluding its CRC field
 
//! @return The register value read
 
uint32_t
JtagDriverSC::readReg1 (uint32_t addr,
int bitSizeNoCrc)
{
// Useful fields and sizes and the register itself
int fullBitSize = bitSizeNoCrc + CRC_LEN;
int dataOffset = bitSizeNoCrc - DR_DATA_LEN;
uint64_t dReg;
 
// Allocate space for the shifted reg and a SystemC completion event
sc_core::sc_event *actionDone = new sc_core::sc_event();
 
// Loop until CRCs match
while (true)
{
// Create the data to shift in
dReg = 0ULL;
dReg |= addr;
uint8_t crc_in = crc8 (dReg, bitSizeNoCrc);
dReg |= (uint64_t)crc_in << bitSizeNoCrc;
 
// Prepare the action, queue it and wait for it to complete
TapActionDRScan *dRScan = new TapActionDRScan (actionDone, dReg,
fullBitSize);
tapActionQueue->write (dRScan);
wait (*actionDone);
dReg = dRScan->getDRegOut ();
delete dRScan;
 
// Check CRCs
uint8_t crc_out = dReg >> bitSizeNoCrc;
uint8_t crc_calc = crc8 (dReg, bitSizeNoCrc);
 
// All done if CRC matches
if (crc_out == crc_calc)
{
delete actionDone;
return (dReg >> dataOffset) & ((1ULL << DR_DATA_LEN) - 1);
}
}
} // readReg1 ()
 
 
//! Single read of an OpenRISC 1000 JTAG register
 
//! Built on top of the JTAG commands to shift registers
//! - Shift-DR the specified address with R/W field unset
//! - read out the data shifted out.
 
//! This version is for "large" values represented as an array of uint64_t.
 
//! @note Must be called from a SystemC thread, because of the use of wait()
 
//! @param[in,out] dRegArray The shift register to use
//! @param[in] addr The address to read
//! @param[in] bitSizeNoCrc Size of the register excluding its CRC field
 
//! @return The register value read
 
uint32_t
JtagDriverSC::readReg1 (uint64_t *dRegArray,
uint32_t addr,
int bitSizeNoCrc)
{
// Useful fields and sizes
int fullBitSize = bitSizeNoCrc + CRC_LEN;
int dataOffset = bitSizeNoCrc - DR_DATA_LEN;
 
// Allocate a SystemC completion event
sc_core::sc_event *actionDone = new sc_core::sc_event();
 
// Loop until CRCs match
while (true)
{
// Create the data to shift in
memset (dRegArray, 0, fullBitSize / 8);
dRegArray[0] |= addr;
uint8_t crc_in = crc8 (dRegArray, bitSizeNoCrc);
insertBits (crc_in, CRC_LEN, dRegArray, bitSizeNoCrc);
 
// Prepare the action, queue it and wait for it to complete
TapActionDRScan *dRScan = new TapActionDRScan (actionDone, dRegArray,
fullBitSize);
tapActionQueue->write (dRScan);
wait (*actionDone);
dRScan->getDRegOut (dRegArray);
delete dRScan;
 
// Check CRCs
uint8_t crc_out = extractBits (dRegArray, bitSizeNoCrc, CRC_LEN);
uint8_t crc_calc = crc8 (dRegArray, bitSizeNoCrc);
 
// All done if CRC matches
if (crc_out == crc_calc)
{
delete actionDone;
return extractBits (dRegArray, dataOffset, DR_DATA_LEN);
}
}
} // readReg1 ()
 
 
//! Write an OpenRISC 1000 JTAG register
 
//! Built on top of the JTAG commands to shift registers
//! - Shift-DR the specified address with R/W field set and data to write
 
//! DR register fields depend on the scan chain in use. For SC_REGISTER:
//! - [4:0] Address to write to
//! - [5] 1 indicating write
//! - [37:6] Value to write
//! - [45:38] CRC (CRC-8-ATM)
 
//! For SC_RISC_DEBUG (i.e. SPRs) and SC_WISHBONE:
//! - [31:0] Address to write to
//! - [32] 1 indicating write
//! - [64:33] Value to write
//! - [72:65] CRC (CRC-8-ATM)
 
//! @note Must be called from a SystemC thread, because of the use of wait()
 
//! @param[in] addr The address of the register
//! @param[in] data The register data to write
 
void
JtagDriverSC::writeReg (uint32_t addr,
uint32_t data)
{
int bitSizeNoCrc; // Size of reg w/o its CRC field
uint64_t writeBit; // Mask for the write enable bit
 
// Determine the size of register to write.
switch (currentScanChain)
{
case OR1K_SC_RISC_DEBUG:
bitSizeNoCrc = RISC_DEBUG_DR_LEN;
writeBit = RISC_DEBUG_RW;
break;
 
case OR1K_SC_REGISTER:
bitSizeNoCrc = REGISTER_DR_LEN;
writeBit = REGISTER_RW;
break;
 
case OR1K_SC_WISHBONE:
bitSizeNoCrc = WISHBONE_DR_LEN;
writeBit = WISHBONE_RW;
break;
}
 
// Create the register in an array
int wordSize = (bitSizeNoCrc + CRC_LEN + 63) / 64;
uint64_t *dReg = new uint64_t [wordSize];
 
// Create the data to shift in
memset (dReg, 0, wordSize * 8);
dReg[0] |= writeBit | addr;
insertBits (data, DR_DATA_LEN, dReg, bitSizeNoCrc - DR_DATA_LEN);
insertBits (crc8 (dReg, bitSizeNoCrc), CRC_LEN, dReg, bitSizeNoCrc);
 
// Prepare the action, queue it and wait for it to complete
sc_core::sc_event *actionDone = new sc_core::sc_event();
TapActionDRScan *dRScan = new TapActionDRScan (actionDone, dReg,
bitSizeNoCrc + CRC_LEN);
 
tapActionQueue->write (dRScan);
wait (*actionDone);
 
delete [] dReg;
delete dRScan;
delete actionDone;
 
} // writeReg ()
 
 
//! Compute CRC-8-ATM
 
//! The data is in a uint64_t, for which we use the first size bits to compute
//! the CRC.
 
//! @Note I am using the same algorithm as the ORPSoC debug unit, but I
//! believe its function is broken! I don't believe the data bit should
//! feature in the computation of bits 2 & 1 of the new CRC.
 
//! @Note I've realized that this is an algorithm for LSB first, so maybe it
//! is correct!
 
//! @param data The data whose CRC is desired
//! @param size The number of bits in the data
 
uint8_t
JtagDriverSC::crc8 (uint64_t data,
int size)
{
uint8_t crc = 0;
 
for (int i = 0; i < size; i++)
{
uint8_t d = data & 1; // Latest data bit
data >>= 1;
 
uint8_t oldCrc7 = (crc >> 7) & 1;
uint8_t oldCrc1 = (crc >> 1) & 1;
uint8_t oldCrc0 = (crc >> 0) & 1;
uint8_t newCrc2 = d ^ oldCrc1 ^ oldCrc7; // Why d?
uint8_t newCrc1 = d ^ oldCrc0 ^ oldCrc7; // Why d?
uint8_t newCrc0 = d ^ oldCrc7;
 
crc = ((crc << 1) & 0xf8) | (newCrc2 << 2) | (newCrc1 << 1) | newCrc0;
}
 
return crc;
 
} // crc8 ()
 
 
//! Compute CRC-8-ATM
 
//! The data is in an array of uint64_t, for which we use the first size bits
//! to compute the CRC.
 
//! @Note I am using the same algorithm as the ORPSoC debug unit, but I
//! believe its function is broken! I don't believe the data bit should
//! feature in the computation of bits 2 & 1 of the new CRC.
 
//! @Note I've realized that this is an algorithm for LSB first, so maybe it
//! is correct!
 
//! @param dataArray The array of data whose CRC is desired
//! @param size The number of bits in the data
 
uint8_t
JtagDriverSC::crc8 (uint64_t dataArray[],
int size)
{
uint8_t crc = 0;
 
for (int i = 0; i < size; i++)
{
uint8_t d = (dataArray[i / 64] >> (i % 64)) & 1;
uint8_t oldCrc7 = (crc >> 7) & 1;
uint8_t oldCrc1 = (crc >> 1) & 1;
uint8_t oldCrc0 = (crc >> 0) & 1;
uint8_t newCrc2 = d ^ oldCrc1 ^ oldCrc7; // Why d?
uint8_t newCrc1 = d ^ oldCrc0 ^ oldCrc7; // Why d?
uint8_t newCrc0 = d ^ oldCrc7;
 
crc = ((crc << 1) & 0xf8) | (newCrc2 << 2) | (newCrc1 << 1) | newCrc0;
}
 
return crc;
 
} // crc8 ()
 
 
//! Utility to insert a string of bits into array
 
//! This is a simple overwriting
 
//! @param str Bits to insert
//! @param strLen Number of bits to insert
//! @param array Array into which to insert
//! @param startBit Offset at which to insert bits
 
void
JtagDriverSC::insertBits (uint64_t str,
int strLen,
uint64_t *array,
int startBit)
{
int startWord = startBit / 64;
int endWord = (startBit + strLen - 1) / 64;
 
startBit = startBit % 64;
 
// Deal with the startWord. Get enough bits for the mask and put them in the
// right place
uint64_t startMask = ((1ULL << strLen) - 1ULL) << startBit;
 
array[startWord] &= ~startMask;
array[startWord] |= str << startBit;
 
// If we were all in one word, we can give up now.
if (startWord == endWord)
{
return;
}
 
// Deal with the endWord. Get enough bits for the mask. No need to shift
// these up - they're always at the bottom of the word
int bitsToDo = (startBit + strLen) % 64;
 
uint64_t endMask = (1ULL << bitsToDo) - 1ULL;
 
array[endWord] &= ~endMask;
array[endWord] |= str >> (strLen - bitsToDo);
 
} // insertBits()
 
 
//! Utility to extract a string of bits from an array
 
//! @param array Array from which to extract
//! @param startBit Offset at which to extract bits
//! @param strLen Number of bits to extract
 
//! @return Extracted bits
 
uint64_t
JtagDriverSC::extractBits (uint64_t *array,
int startBit,
int strLen)
{
int startWord = startBit / 64;
int endWord = (startBit + strLen - 1) / 64;
 
startBit = startBit % 64;
 
// Deal with the startWord. Get enough bits for the mask and put them in the
// right place
uint64_t startMask = ((1ULL << strLen) - 1ULL) << startBit;
uint64_t res = (array[startWord] & startMask) >> startBit;
 
// If we were all in one word, we can give up now.
if (startWord == endWord)
{
return res;
}
 
// Deal with the endWord. Get enough bits for the mask. No need to shift
// these up - they're always at the bottom of the word
int bitsToDo = (startBit + strLen) % 64;
uint64_t endMask = (1ULL << bitsToDo) - 1ULL;
 
return res | ((array[endWord] & endMask) << (strLen - bitsToDo));
 
} // extractBits ()
/src/OrpsocAccess.cpp
41,8 → 41,9
#include "Vorpsoc_top_or1200_dpram.h"
//#include "Vorpsoc_top_ram_wb.h"
//#include "Vorpsoc_top_ram_wb_sc_sw.h"
#include "Vorpsoc_top_ram_wb__D20_A18_M800000.h"
#include "Vorpsoc_top_ram_wb_sc_sw__D20_A18_M800000.h"
#include "Vorpsoc_top_ram_wb__D20_A19_M800000.h"
#include "Vorpsoc_top_ram_wb_sc_sw__D20_A19_M800000.h"
#include "Vorpsoc_top_wb_conbus_top__pi1.h"
 
//! Constructor for the ORPSoC access class
 
53,11 → 54,15
 
OrpsocAccess::OrpsocAccess (Vorpsoc_top *orpsoc_top)
{
// Assign processor accessor objects
or1200_ctrl = orpsoc_top->v->i_or1k->i_or1200_top->or1200_cpu->or1200_ctrl;
or1200_except = orpsoc_top->v->i_or1k->i_or1200_top->or1200_cpu->or1200_except;
or1200_sprs = orpsoc_top->v->i_or1k->i_or1200_top->or1200_cpu->or1200_sprs;
rf_a = orpsoc_top->v->i_or1k->i_or1200_top->or1200_cpu->or1200_rf->rf_a;
// Assign main memory accessor objects
ram_wb_sc_sw = orpsoc_top->v->ram_wb0->ram0;
// Assign arbiter accessor object
wb_arbiter = orpsoc_top->v->wb_conbus;
 
} // OrpsocAccess ()
 
273,3 → 278,129
 
} // getSprEsr ()
 
 
//! Access for the arbiter's grant signal
 
//! @return The value of the wb_conmax_top.arb signal
 
uint8_t
OrpsocAccess::getWbArbGrant ()
{
return (wb_arbiter->get_gnt) ();
 
} // getWbArbGrant ()
 
 
//! Arbiter master[mast_num] access functions
 
//! Access for the arbiter's master[mast_num] data in signal
 
//! @return The value of the wb_conmax_top.m_dat_i[mast_num]
 
uint32_t
OrpsocAccess::getWbArbMastDatI (uint32_t mast_num)
{
return (wb_arbiter->get_m_dat_i) (mast_num);
 
} // getWbArbMastDatI ()
 
//! Access for the arbiter's master[mast_num] data out signal
 
//! @return The value of the wb_conmax_top.m_dat_o[mast_num]
 
uint32_t
OrpsocAccess::getWbArbMastDatO (uint32_t mast_num)
{
return (wb_arbiter->get_m_dat_o) (mast_num);
 
} // getWbArbMastDatO ()
 
//! Access for the arbiter's master[mast_num] data out
 
//! @return The value of the wb_conmax_top.m_adr_i[mast_num]
 
uint32_t
OrpsocAccess::getWbArbMastAdrI (uint32_t mast_num)
{
return (wb_arbiter->get_m_adr_i) (mast_num);
 
} // getWbArbMastAdrI ()
 
 
//! Access for the arbiter's master[mast_num] select signal
 
//! @return The value of the wb_conmax_top.m_sel_i[mast_num]
 
uint8_t
OrpsocAccess::getWbArbMastSelI (uint32_t mast_num)
{
return (wb_arbiter->get_m_sel_i) (mast_num);
 
} // getWbArbMastSelI ()
 
//! Access for the arbiter's master[mast_num] decoded slave select signal
 
//! @return The value of the wb_conmax_top.m_ssel_dec[mast_num]
 
uint8_t
OrpsocAccess::getWbArbMastSlaveSelDecoded (uint32_t mast_num)
{
return (wb_arbiter->get_m_ssel_dec) (mast_num);
 
} // getWbArbMastSlaveSelDecoded ()
 
//! Access for the arbiter's master[mast_num] write enable signal
 
//! @return The value of the wb_conmax_top.m_we_i[mast_num]
 
bool
OrpsocAccess::getWbArbMastWeI (uint32_t mast_num)
{
return (wb_arbiter->get_m_we_i) (mast_num);
 
} // getWbArbMastWeI ()
 
//! Access for the arbiter's master[mast_num] cycle input signal
 
//! @return The value of the wb_conmax_top.m_cyc_i[mast_num]
 
bool
OrpsocAccess::getWbArbMastCycI (uint32_t mast_num)
{
return (wb_arbiter->get_m_cyc_i) (mast_num);
 
} // getWbArbMastCycI ()
 
//! Access for the arbiter's master[mast_num] strobe input signal
 
//! @return The value of the wb_conmax_top.m_stb_i[mast_num]
 
bool
OrpsocAccess::getWbArbMastStbI (uint32_t mast_num)
{
return (wb_arbiter->get_m_stb_i) (mast_num);
 
} // getWbArbMastStbI ()
 
//! Access for the arbiter's master[mast_num] ACK output signal
 
//! @return The value of the wb_conmax_top.m_ack_o[mast_num]
 
bool
OrpsocAccess::getWbArbMastAckO (uint32_t mast_num)
{
return (wb_arbiter->get_m_ack_o) (mast_num);
 
} // getWbArbMastAckO ()
 
//! Access for the arbiter's master[mast_num] error input signal
 
//! @return The value of the wb_conmax_top.m_err_o[mast_num]
 
bool
OrpsocAccess::getWbArbMastErrO (uint32_t mast_num)
{
return (wb_arbiter->get_m_err_o) (mast_num);
 
} // getWbArbMastErrO ()
 
/src/SprCache.cpp
0,0 → 1,150
// ----------------------------------------------------------------------------
 
// Debug Unit SPR cache: implementation
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// 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.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: SprCache.cpp 331 2009-03-12 17:01:48Z jeremy $
 
#include <iostream>
#include <cstring>
 
#include "SprCache.h"
 
 
//-----------------------------------------------------------------------------
//! Constructor
 
//! Allocate tables and clear the cache
 
//! @param[in] _tableSize The desire hash table size. A prime number is
//! recommended.
//-----------------------------------------------------------------------------
SprCache::SprCache (int _tableSize) :
tableSize (_tableSize)
{
sprIsValid = new bool [tableSize];
sprKeyNum = new uint16_t [tableSize];
sprValue = new uint32_t [tableSize];
 
clear ();
 
} // SprCache ()
 
 
//-----------------------------------------------------------------------------
//! Destructor
 
//! Free up the tables
//-----------------------------------------------------------------------------
SprCache::~SprCache ()
{
delete [] sprValue;
delete [] sprKeyNum;
delete [] sprIsValid;
 
} // ~SprCache ()
 
 
//! Empty the hash table
 
//! Only need to worry about the validity field
void
SprCache::clear ()
{
memset (sprIsValid, false, tableSize);
 
// No more than 70% full
maxToUse = tableSize * 7 / 10;
 
} // clear ()
 
 
//-----------------------------------------------------------------------------
//! Write a new value into the cache
 
//! If the hash table is full silently does nothing, unless the force
//! parameter is set to TRUE. Under this circumstance the value WILL be
//! written into the hash table. This is safe, because the table is never more
//! than 70% full, and force is used only for NPC.
 
//! @param[in] spr The SPR being written to
//! @param[in] value The value to write
//! @param[in] force If TRUE the value will be written to the hash table,
//! even if it is too full.
//-----------------------------------------------------------------------------
void
SprCache::write (uint16_t sprNum,
uint32_t value,
bool force)
{
if (maxToUse <= 0)
{
return; // Table is full
}
 
int hv = sprNum % tableSize;
 
// We can use the slot if either it is empty, or it is full and the key
// number matches.
while (sprIsValid[hv] && (sprKeyNum[hv] != sprNum))
{
hv = (hv + 1) % tableSize;
}
 
sprIsValid[hv] = true;
sprKeyNum[hv] = sprNum;
sprValue[hv] = value;
maxToUse--;
 
} // write ()
 
 
//-----------------------------------------------------------------------------
//! Try to read a value from the cache
 
//! The entry must be valid.
 
//! @param[in] sprNum The SPR being read from
//! @param[out] value The value read. Will be written, even if the value is
//! not valid.
 
//! @return True if the value was found in the hash table
//-----------------------------------------------------------------------------
bool
SprCache::read (uint16_t sprNum,
uint32_t &value)
{
int hv = sprNum % tableSize;
 
// Look for either an empty slot (we are not there) or a matching key (we
// are there)
while (sprIsValid[hv] && (sprKeyNum[hv] != sprNum))
{
hv = (hv + 1) % tableSize;
}
 
value = sprValue[hv];
return sprIsValid[hv];
 
} // read ()
/src/RspPacket.cpp
0,0 → 1,156
// ----------------------------------------------------------------------------
 
// RSP packet: implementation
 
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
 
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
// This file is part of the cycle accurate model of the OpenRISC 1000 based
// system-on-chip, ORPSoC, built using Verilator.
 
// 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
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
 
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
 
// 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/>.
 
// ----------------------------------------------------------------------------
 
// $Id: RspPacket.cpp 327 2009-03-07 19:10:56Z jeremy $
 
#include <iomanip>
#include <iostream>
#include <cstring>
#include <cerrno>
#include <cstdio>
 
#include "RspPacket.h"
#include "Utils.h"
 
 
using std::ostream;
using std::cerr;
using std::dec;
using std::endl;
using std::hex;
using std::setfill;
using std::setw;
 
 
//-----------------------------------------------------------------------------
//! Constructor
 
//! Allocate the new data buffer
 
//! @param[in] _rspConnection The RSP connection we will use
//! @param[in] _bufSize Size of data buffer to allocate
//-----------------------------------------------------------------------------
RspPacket::RspPacket (int _bufSize) :
bufSize (_bufSize)
{
data = new char [_bufSize];
 
} // RspPacket ();
 
 
//-----------------------------------------------------------------------------
//! Destructor
 
//! Give back the data buffer
//-----------------------------------------------------------------------------
RspPacket::~RspPacket ()
{
delete [] data;
 
} // ~RspPacket ()
 
 
//-----------------------------------------------------------------------------
//! Pack a string into a packet.
 
//! A convenience version of this method.
 
//! @param str The string to copy into the data packet before sending
//-----------------------------------------------------------------------------
void
RspPacket::packStr (const char *str)
{
int slen = strlen (str);
 
// Construct the packet to send, so long as string is not too big, otherwise
// truncate. Add EOS at the end for convenient debug printout
if (slen >= bufSize)
{
cerr << "Warning: String \"" << str
<< "\" too large for RSP packet: truncated\n" << endl;
slen = bufSize - 1;
}
 
strncpy (data, str, slen);
data[slen] = 0;
len = slen;
 
} // packStr ()
 
//-----------------------------------------------------------------------------
//! Get the data buffer size
 
//! @return The data buffer size
//-----------------------------------------------------------------------------
int
RspPacket::getBufSize ()
{
return bufSize;
 
} // getBufSize ()
 
 
//-----------------------------------------------------------------------------
//! Get the current number of chars in the data buffer
 
//! @return The number of chars in the data buffer
//-----------------------------------------------------------------------------
int
RspPacket::getLen ()
{
return len;
 
} // getLen ()
 
 
//-----------------------------------------------------------------------------
//! Set the number of chars in the data buffer
 
//! @param[in] _len The number of chars to be set
//-----------------------------------------------------------------------------
void
RspPacket::setLen (int _len)
{
len = _len;
 
} // setLen ()
 
 
//-----------------------------------------------------------------------------
//! Output stream operator
 
//! @param[out] s Stream to output to
//! @param[in] p Packet to output
//-----------------------------------------------------------------------------
ostream &
operator<< (ostream &s,
RspPacket &p)
{
return s << "RSP packet: " << std::dec << std::setw (3) << p.getLen()
<< std::setw (0) << " chars, \"" << p.data << "\"";
 
} // operator<< ()

powered by: WebSVN 2.1.0

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