URL
https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk
Subversion Repositories openrisc_me
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 62 to Rev 63
- ↔ Reverse comparison
Rev 62 → Rev 63
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/include/UartSC.h
26,6 → 26,7
#define UART_SC__H |
|
#include "systemc.h" |
#include <stdint.h> |
|
//! Handle UART I/O |
|
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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" |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
|
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
|
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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 |
|
/openrisc/trunk/orpsocv2/bench/sysc/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); |
/openrisc/trunk/orpsocv2/bench/sysc/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", ®Num)) |
{ |
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", ®Num, 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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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; |
|
/openrisc/trunk/orpsocv2/bench/sysc/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() |
/openrisc/trunk/orpsocv2/bench/sysc/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() |
/openrisc/trunk/orpsocv2/bench/sysc/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; |
} |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
|
|
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
|
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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 () |
/openrisc/trunk/orpsocv2/bench/sysc/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<< () |
/openrisc/trunk/orpsocv2/rtl/verilog/or1200_defines.v
514,7 → 514,7
// |
// To implement divide, multiplier needs to be implemented. |
// |
//`define OR1200_IMPL_DIV |
`define OR1200_IMPL_DIV |
|
// |
// Implement rotate in the ALU |
572,7 → 572,7
// |
// Implement HW Single Precision FPU |
// |
//`define OR1200_FPU_IMPLEMENTED |
`define OR1200_FPU_IMPLEMENTED |
|
// |
// Clock ratio RISC clock versus WB clock |
751,7 → 751,11
// |
`ifdef OR1200_FPU_IMPLEMENTED |
`define OR1200_FPUOP_WIDTH 8 |
/* FPU unit from Usselman takes 5 cycles from decode, so 4 ex. cycles */ |
`define OR1200_FPUOP_CYCLES 3'd4 |
/* FP instruction is double precision if bit 4 is set. We're a 32-bit |
implementation thus do not support double precision FP */ |
`define OR1200_FPUOP_DOUBLE_BIT 4 |
`define OR1200_FPUOP_ADD 8'b0000_0000 |
`define OR1200_FPUOP_SUB 8'b0000_0001 |
`define OR1200_FPUOP_MUL 8'b0000_0010 |
/openrisc/trunk/orpsocv2/rtl/verilog/components/wb_conbus/wb_conbus_top.v
369,7 → 369,7
// |
|
wire [`mselectw -1:0] i_gnt_arb; |
wire [2:0] gnt; |
wire [2:0] gnt/* verilator public */; |
reg [`sselectw -1:0] i_ssel_dec; |
`ifdef WB_USE_TRISTATE |
wire [`mbusw -1:0] i_bus_m; |
639,7 → 639,7
////////////////////////////////// |
// address decode logic |
// |
wire [7:0] m0_ssel_dec, m1_ssel_dec, m2_ssel_dec, m3_ssel_dec, m4_ssel_dec, m5_ssel_dec, m6_ssel_dec, m7_ssel_dec; |
wire [7:0] m0_ssel_dec, m1_ssel_dec, m2_ssel_dec, m3_ssel_dec, m4_ssel_dec, m5_ssel_dec, m6_ssel_dec, m7_ssel_dec ; |
always @(gnt, m0_ssel_dec, m1_ssel_dec, m2_ssel_dec, m3_ssel_dec, m4_ssel_dec, m5_ssel_dec, m6_ssel_dec, m7_ssel_dec) |
case(gnt) |
3'h0: i_ssel_dec = m0_ssel_dec; |
762,4 → 762,170
//assign i_ssel_dec[7] = (i_bus_m[`mbusw -1 : `mbusw - s27_addr_w ] == s7_addr); |
|
|
`ifdef verilator |
// Access functions for verilator, hardcoded to dw=32, aw=32 |
|
// Master Signal Access functions |
|
wire [`dw-1:0] m_dat_i[0:`mselectw-1] /* verilator public */; |
assign m_dat_i[0] = m0_dat_i; |
assign m_dat_i[1] = m1_dat_i; |
assign m_dat_i[2] = m2_dat_i; |
assign m_dat_i[3] = m3_dat_i; |
assign m_dat_i[4] = m4_dat_i; |
assign m_dat_i[5] = m5_dat_i; |
assign m_dat_i[6] = m6_dat_i; |
assign m_dat_i[7] = m7_dat_i; |
|
wire [`dw-1:0] m_dat_o[0:`mselectw-1]/* verilator public */; |
assign m_dat_o[0] = m0_dat_o; |
assign m_dat_o[1] = m1_dat_o; |
assign m_dat_o[2] = m2_dat_o; |
assign m_dat_o[3] = m3_dat_o; |
assign m_dat_o[4] = m4_dat_o; |
assign m_dat_o[5] = m5_dat_o; |
assign m_dat_o[6] = m6_dat_o; |
assign m_dat_o[7] = m7_dat_o; |
|
|
wire [`aw-1:0] m_adr_i[0:`mselectw-1]/* verilator public */; |
assign m_adr_i[0] = m0_adr_i; |
assign m_adr_i[1] = m1_adr_i; |
assign m_adr_i[2] = m2_adr_i; |
assign m_adr_i[3] = m3_adr_i; |
assign m_adr_i[4] = m4_adr_i; |
assign m_adr_i[5] = m5_adr_i; |
assign m_adr_i[6] = m6_adr_i; |
assign m_adr_i[7] = m7_adr_i; |
|
wire [`sw-1:0] m_sel_i[0:`mselectw-1]/* verilator public */; |
assign m_sel_i[0] = m0_sel_i; |
assign m_sel_i[1] = m1_sel_i; |
assign m_sel_i[2] = m2_sel_i; |
assign m_sel_i[3] = m3_sel_i; |
assign m_sel_i[4] = m4_sel_i; |
assign m_sel_i[5] = m5_sel_i; |
assign m_sel_i[6] = m6_sel_i; |
assign m_sel_i[7] = m7_sel_i; |
|
wire [`mselectw-1:0] m_we_i/* verilator public */; |
assign m_we_i[0] = m0_we_i; |
assign m_we_i[1] = m1_we_i; |
assign m_we_i[2] = m2_we_i; |
assign m_we_i[3] = m3_we_i; |
assign m_we_i[4] = m4_we_i; |
assign m_we_i[5] = m5_we_i; |
assign m_we_i[6] = m6_we_i; |
assign m_we_i[7] = m7_we_i; |
|
wire [`mselectw-1:0] m_cyc_i/* verilator public */; |
assign m_cyc_i[0] = m0_cyc_i; |
assign m_cyc_i[1] = m1_cyc_i; |
assign m_cyc_i[2] = m2_cyc_i; |
assign m_cyc_i[3] = m3_cyc_i; |
assign m_cyc_i[4] = m4_cyc_i; |
assign m_cyc_i[5] = m5_cyc_i; |
assign m_cyc_i[6] = m6_cyc_i; |
assign m_cyc_i[7] = m7_cyc_i; |
|
wire [`mselectw-1:0] m_stb_i/* verilator public */; |
assign m_stb_i[0] = m0_stb_i; |
assign m_stb_i[1] = m1_stb_i; |
assign m_stb_i[2] = m2_stb_i; |
assign m_stb_i[3] = m3_stb_i; |
assign m_stb_i[4] = m4_stb_i; |
assign m_stb_i[5] = m5_stb_i; |
assign m_stb_i[6] = m6_stb_i; |
assign m_stb_i[7] = m7_stb_i; |
|
wire [`mselectw-1:0] m_ack_o/* verilator public */; |
assign m_ack_o[0] = m0_ack_o; |
assign m_ack_o[1] = m1_ack_o; |
assign m_ack_o[2] = m2_ack_o; |
assign m_ack_o[3] = m3_ack_o; |
assign m_ack_o[4] = m4_ack_o; |
assign m_ack_o[5] = m5_ack_o; |
assign m_ack_o[6] = m6_ack_o; |
assign m_ack_o[7] = m7_ack_o; |
|
wire [`mselectw-1:0] m_err_o/* verilator public */; |
assign m_err_o[0] = m0_err_o; |
assign m_err_o[1] = m1_err_o; |
assign m_err_o[2] = m2_err_o; |
assign m_err_o[3] = m3_err_o; |
assign m_err_o[4] = m4_err_o; |
assign m_err_o[5] = m5_err_o; |
assign m_err_o[6] = m6_err_o; |
assign m_err_o[7] = m7_err_o; |
|
wire [7:0] m_ssel_dec [0:7]/* verilator public*/; |
assign m_ssel_dec[0] = m0_ssel_dec; |
assign m_ssel_dec[1] = m1_ssel_dec; |
assign m_ssel_dec[2] = m2_ssel_dec; |
assign m_ssel_dec[3] = m3_ssel_dec; |
assign m_ssel_dec[4] = m4_ssel_dec; |
assign m_ssel_dec[5] = m5_ssel_dec; |
assign m_ssel_dec[6] = m6_ssel_dec; |
assign m_ssel_dec[7] = m7_ssel_dec; |
|
// Arbiter's grant signal |
function [2:0] get_gnt; |
// verilator public |
get_gnt = gnt; |
endfunction |
|
function [31:0] get_m_dat_i; |
// verilator public |
input [2:0] mast_no; |
get_m_dat_i = m_dat_i[mast_no]; |
endfunction // get_m_dat_i |
function [31:0] get_m_dat_o; |
// verilator public |
input [2:0] mast_no; |
get_m_dat_o = m_dat_o[mast_no]; |
endfunction // get_m_dat_o |
function [31:0] get_m_adr_i; |
// verilator public |
input [2:0] mast_no; |
get_m_adr_i = m_adr_i[mast_no]; |
endfunction // get_m_adr_i |
function [3:0] get_m_sel_i; |
// verilator public |
input [2:0] mast_no; |
get_m_sel_i = m_sel_i[mast_no]; |
endfunction // get_m_sel_i |
function get_m_we_i; |
// verilator public |
input [2:0] mast_no; |
get_m_we_i = m_we_i[mast_no]; |
endfunction // get_m_we_i |
function get_m_cyc_i; |
// verilator public |
input [2:0] mast_no; |
get_m_cyc_i = m_cyc_i[mast_no]; |
endfunction // get_m_cyc_i |
function get_m_stb_i; |
// verilator public |
input [2:0] mast_no; |
get_m_stb_i = m_stb_i[mast_no]; |
endfunction // get_m_stb_i |
function get_m_ack_o; |
// verilator public |
input [2:0] mast_no; |
get_m_ack_o = m_ack_o[mast_no]; |
endfunction // get_m_ack_o |
function get_m_err_o; |
// verilator public |
input [2:0] mast_no; |
get_m_err_o = m_err_o[mast_no]; |
endfunction // get_m_err_o |
|
// Decoded slave for each master's access |
function [7:0] get_m_ssel_dec; |
// verilator public |
input [2:0] mast_no; |
get_m_ssel_dec = m_ssel_dec[mast_no]; |
endfunction |
|
`endif |
endmodule |
/openrisc/trunk/orpsocv2/rtl/verilog/components/debug_if/dbg_cpu.v
280,7 → 280,7
dr[31:0] <= #1 input_data[31:0]; |
latch_data <= #1 1'b1; |
end |
else |
else if (enable) |
begin |
dr[31:0] <= #1 {dr[30:0], 1'b0}; |
latch_data <= #1 1'b0; |
/openrisc/trunk/orpsocv2/rtl/verilog/components/or1200r2/or1200_du.v
1111,6 → 1111,10
case (dcr0[`OR1200_DU_DCR_CT]) // synopsys parallel_case |
3'b000: match_cond0_stb = 1'b0; //comparison disabled |
3'b001: match_cond0_stb = 1'b1; // insn fetch EA |
3'b010: match_cond0_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b011: match_cond0_stb = dcpu_cycstb_i & dcpu_we_i;// store |
3'b100: match_cond0_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b101: match_cond0_stb = dcpu_cycstb_i & dcpu_we_i;// store |
default:match_cond0_stb = dcpu_cycstb_i; // any load/store |
endcase |
|
1185,7 → 1189,11
case (dcr1[`OR1200_DU_DCR_CT]) // synopsys parallel_case |
3'b000: match_cond1_stb = 1'b0; //comparison disabled |
3'b001: match_cond1_stb = 1'b1; // insn fetch EA |
default:match_cond1_stb = dcpu_cycstb_i; // any load/store |
3'b010: match_cond1_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b011: match_cond1_stb = dcpu_cycstb_i & dcpu_we_i;// store |
3'b100: match_cond1_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b101: match_cond1_stb = dcpu_cycstb_i & dcpu_we_i;// store |
default:match_cond1_stb = dcpu_cycstb_i; // any load/store |
endcase |
|
// |
1252,6 → 1260,11
case (dcr2[`OR1200_DU_DCR_CT]) // synopsys parallel_case |
3'b000: match_cond2_stb = 1'b0; //comparison disabled |
3'b001: match_cond2_stb = 1'b1; // insn fetch EA |
3'b010: match_cond2_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b011: match_cond2_stb = dcpu_cycstb_i & dcpu_we_i;// store |
3'b100: match_cond2_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b101: match_cond2_stb = dcpu_cycstb_i & dcpu_we_i;// store |
|
default:match_cond2_stb = dcpu_cycstb_i; // any load/store |
endcase |
|
1320,6 → 1333,11
case (dcr3[`OR1200_DU_DCR_CT]) // synopsys parallel_case |
3'b000: match_cond3_stb = 1'b0; //comparison disabled |
3'b001: match_cond3_stb = 1'b1; // insn fetch EA |
3'b010: match_cond3_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b011: match_cond3_stb = dcpu_cycstb_i & dcpu_we_i;// store |
3'b100: match_cond3_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b101: match_cond3_stb = dcpu_cycstb_i & dcpu_we_i;// store |
|
default:match_cond3_stb = dcpu_cycstb_i; // any load/store |
endcase |
|
1388,6 → 1406,11
case (dcr4[`OR1200_DU_DCR_CT]) // synopsys parallel_case |
3'b000: match_cond4_stb = 1'b0; //comparison disabled |
3'b001: match_cond4_stb = 1'b1; // insn fetch EA |
3'b010: match_cond4_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b011: match_cond4_stb = dcpu_cycstb_i & dcpu_we_i;// store |
3'b100: match_cond4_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b101: match_cond4_stb = dcpu_cycstb_i & dcpu_we_i;// store |
|
default:match_cond4_stb = dcpu_cycstb_i; // any load/store |
endcase |
|
1457,6 → 1480,11
case (dcr5[`OR1200_DU_DCR_CT]) // synopsys parallel_case |
3'b000: match_cond5_stb = 1'b0; //comparison disabled |
3'b001: match_cond5_stb = 1'b1; // insn fetch EA |
3'b010: match_cond5_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b011: match_cond5_stb = dcpu_cycstb_i & dcpu_we_i;// store |
3'b100: match_cond5_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b101: match_cond5_stb = dcpu_cycstb_i & dcpu_we_i;// store |
|
default:match_cond5_stb = dcpu_cycstb_i; // any load/store |
endcase |
|
1525,6 → 1553,11
case (dcr6[`OR1200_DU_DCR_CT]) // synopsys parallel_case |
3'b000: match_cond6_stb = 1'b0; //comparison disabled |
3'b001: match_cond6_stb = 1'b1; // insn fetch EA |
3'b010: match_cond6_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b011: match_cond6_stb = dcpu_cycstb_i & dcpu_we_i;// store |
3'b100: match_cond6_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b101: match_cond6_stb = dcpu_cycstb_i & dcpu_we_i;// store |
|
default:match_cond6_stb = dcpu_cycstb_i; // any load/store |
endcase |
|
1594,6 → 1627,11
case (dcr7[`OR1200_DU_DCR_CT]) // synopsys parallel_case |
3'b000: match_cond7_stb = 1'b0; //comparison disabled |
3'b001: match_cond7_stb = 1'b1; // insn fetch EA |
3'b010: match_cond7_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b011: match_cond7_stb = dcpu_cycstb_i & dcpu_we_i;// store |
3'b100: match_cond7_stb = dcpu_cycstb_i & ~dcpu_we_i;// load |
3'b101: match_cond7_stb = dcpu_cycstb_i & dcpu_we_i;// store |
|
default:match_cond7_stb = dcpu_cycstb_i; // any load/store |
endcase |
|
/openrisc/trunk/orpsocv2/rtl/verilog/components/or1200r2/or1200_ctrl.v
684,9 → 684,6
`ifdef OR1200_MAC_IMPLEMENTED |
`OR1200_OR32_MACMSB, |
`endif |
`ifdef OR1200_FPU_IMPLEMENTED |
`OR1200_OR32_FLOAT, |
`endif |
`OR1200_OR32_SW, |
`OR1200_OR32_SB, |
`OR1200_OR32_SH, |
697,7 → 694,13
`endif |
`OR1200_OR32_NOP: |
except_illegal <= #1 1'b0; |
`ifdef OR1200_FPU_IMPLEMENTED |
`OR1200_OR32_FLOAT: |
/* Check it's not a double instruction */ |
except_illegal <= #1 id_insn[`OR1200_FPUOP_DOUBLE_BIT]; |
`endif |
|
|
// Illegal and OR1200 unsupported instructions |
default: |
except_illegal <= #1 1'b1; |
1115,6 → 1118,9
sig_trap <= #1 (id_insn[31:23] == {`OR1200_OR32_XSYNC, 3'b010}) |
| du_hwbkpt; |
end |
else if (!sig_trap) |
sig_trap <= #1 du_hwbkpt; // Added jb 091220 - because hw data load/store EA bkpts weren't getting triggered |
|
end |
|
endmodule |
/openrisc/trunk/orpsocv2/rtl/verilog/orpsoc_top.v
679,7 → 679,7
`else // !`ifdef USE_SDRAM |
|
parameter ram_wb_dat_width = 32; |
parameter ram_wb_adr_width = 24; |
parameter ram_wb_adr_width = 25; |
//parameter ram_wb_mem_size = 2097152; // 8MB |
parameter ram_wb_mem_size = 8388608; // 32MB -- for linux test |
|
/openrisc/trunk/orpsocv2/sim/bin/Makefile
583,15 → 583,24
|
# If set on the command line we build the cycle accurate model which will generate verilator-specific profiling information. This is useful for checking the efficiency of the model - not really useful for checking code or the function of the model. |
ifdef VLT_ORPSOC_PROFILING |
VLT_CPPFLAGS=-g -pg |
VLT_CPPFLAGS +=-pg |
VLT_DEBUG_OPTIONS +=-profile-cfuncs |
else |
VLT_CPPFLAGS=-fbranch-probabilities -fvpt -funroll-loops -fpeel-loops -ftracer -O3 |
#VLT_CPPFLAGS +=-fbranch-probabilities -fvpt -funroll-loops -fpeel-loops -ftracer -O3 |
VLT_CPPFLAGS +=-fprofile-use -Wcoverage-mismatch |
#VLT_CPPFLAGS=-Wall |
endif |
|
# Set VLT_IN_GDB=1 when making if going to run the cycle accurate model executable in GDB to check suspect behavior. This also removes optimisation. |
ifdef VLT_IN_GDB |
VLT_CPPFLAGS +=-g -O0 |
else |
# The default optimisation flag applied to all of the cycle accurate model files |
VLT_CPPFLAGS +=-O3 |
endif |
|
ifdef VLT_DO_PROFILING |
VLT_CPPFLAGS=-O3 -ftest-coverage -fprofile-generate |
VLT_CPPFLAGS +=-ftest-coverage -fprofile-arcs -fprofile-generate |
endif |
|
# VCD Enabled by default when building, enable it at runtime |
609,7 → 618,7
# Included is the SystemPerl trace model |
SYSC_MODELS_BUILD=$(SYSC_MODELS) $(VLT_TRACEOBJ) |
|
prepare-vlt: prepare-rtl vlt_model_links $(SIM_VLT_DIR)/Vorpsoc_top |
prepare-vlt: prepare-rtl vlt-model-links $(SIM_VLT_DIR)/Vorpsoc_top |
@echo;echo "\tCycle-accurate model compiled successfully" |
@echo;echo "\tRun the executable with the -h option for usage instructions:";echo |
$(SIM_VLT_DIR)/Vorpsoc_top -h |
688,8 → 697,8
-e s!\$$BACKEND_DIR!$(BACKEND_DIR)! \ |
-e \\!^//.*\$$!d -e \\!^\$$!d; |
|
.PHONY: vlt_model_links |
vlt_model_links: |
.PHONY: vlt-model-links |
vlt-model-links: |
# Link all the required system C model files into the verilator work dir |
@echo; echo "\tLinking SystemC model source to verilator build path"; echo |
@if [ ! -d $(SIM_VLT_DIR) ]; then mkdir $(SIM_VLT_DIR); fi |
742,8 → 751,18
# This new make target copies athe results of the profiling back to the right |
# paths before we create everything again |
############################################################################### |
prepare-vlt-profiled: vlt_restore-profileoutput prepare-rtl vlt-model-links $(SIM_VLT_DIR)/Vorpsoc_top |
.PHONY: prepare-vlt-profiled |
prepare-vlt-profiled: $(SIM_VLT_DIR)/OrpsocMain.gcda clean vlt-restore-profileoutput prepare-rtl vlt-model-links $(SIM_VLT_DIR)/Vorpsoc_top |
|
$(SIM_VLT_DIR)/OrpsocMain.gcda: $(SIM_VLT_DIR)/Vorpsoc_top-for-profiling prepare-sw-uart-printf |
$(MAKE) -C $(SW_DIR)/dhry dhry-nocache-O2 NUM_RUNS=200 |
$(SIM_VLT_DIR)/Vorpsoc_top -f $(SW_DIR)/dhry/dhry-nocache-O2.or32 -v -l sim.log --crash-monitor |
|
.PHONY: $(SIM_VLT_DIR)/Vorpsoc_top-for-profiling |
$(SIM_VLT_DIR)/Vorpsoc_top-for-profiling: |
$(MAKE) prepare-vlt VLT_DO_PROFILING=1 |
|
.PHONY: vlt-restore-profileoutput |
vlt-restore-profileoutput: |
@echo;echo "\tRestoring profiling outputs"; echo |
$(Q)mkdir -p ../vlt |
/openrisc/trunk/orpsocv2/sw/utils/Makefile
42,16 → 42,22
## Makefile for the ORPSoC software utilities |
## |
|
PROGRAMS = bin2c bin2srec bin2flimg bin2hex bin2vmem |
PROGRAMS = bin2c bin2srec bin2flimg bin2hex bin2vmem binlog2readable |
# NB: 'loader' not in that list |
|
CC = gcc |
CPP = g++ |
CFLAGS = -O2 -Wall |
#CFLAGS = -O0 -Wall -g |
|
% : %.c |
@/bin/rm -f $@ |
$(CC) -o $@ $(CFLAGS) $< |
|
% : %.cpp |
@/bin/rm -f $@ |
$(CPP) -o $@ $(CFLAGS) $< |
|
all: $(PROGRAMS) or32-idecode |
|
# redundant stanza: |
/openrisc/trunk/orpsocv2/sw/utils/binlog2readable.cpp
0,0 → 1,294
// ---------------------------------------------------------------------------- |
|
// Interprets ORPSoC's Cycle Accurate model binary format log files |
|
// Contributor Julius Baxter <jb@orsoc.se> |
|
// 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 <string.h> |
#include <iostream> |
#include <iomanip> |
#include <cstdlib> |
#include <stdint.h> |
#include <fstream> |
#include <sys/types.h> |
|
using namespace std; |
|
|
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 printUsage() |
{ |
cerr << endl << "Error: No input file specified." << endl; |
cerr << endl; |
cerr << "Usage: binlog2readable <options> <file>" << endl; |
cerr << endl; |
cerr << "Convert binary formatted ORPSoC execution log <file> to human readable format" << endl; |
|
cerr << "Options:" << endl; |
cerr << " -o <file>\tOutput file, if not specified stdout is used" << endl; |
cerr << " --skip <num>\tSkip <num> instructions from the front of the log" << endl; |
cerr << " --last <num>\tPrint the last <num> instructions from the end of the log" << endl; |
cerr << endl; |
|
} |
|
int main(int argc, char **argv) |
{ |
ifstream inFile; |
ofstream outFile; /* Anyone know how to make these things into stdouts?? */ |
unsigned long long filesize; |
int using_std_out = 1; /* Default out is to stdout */ |
char reg_vals_included; |
int skip_insns = 0; |
int skip_insns_from_end = -1; |
struct s_binary_output_buffer buf; |
struct s_binary_output_buffer_sans_regs buf_sans_regs; |
|
if (argc < 2) |
{ |
printUsage(); |
return 1; |
} |
|
for(int i=1; i < argc; i++) |
{ |
if ((strcmp(argv[i], "-s")==0) || |
(strcmp(argv[i], "--skip")==0)) |
{ |
if (i+1 < argc) |
if(argv[i+1][0] != '-') |
{ |
skip_insns = atoi(argv[i+1]); |
skip_insns_from_end = 0; |
i++; |
} |
} |
else if (strcmp(argv[i], "--last")==0) |
{ |
if (i+1 < argc) |
if(argv[i+1][0] != '-') |
{ |
skip_insns = atoi(argv[i+1]); |
skip_insns_from_end = 1; |
i++; |
} |
} |
else if (strcmp(argv[i], "-o")==0) |
{ |
if (i+1 < argc) |
if(argv[i+1][0] != '-') |
{ |
/* Were given a file to output to */ |
outFile.open(argv[i+1], ios::out); |
if (!outFile.is_open()) |
{ |
cerr << "Error: unable to open file " << argv[2] << " for writing." << endl; |
if (inFile.is_open()) inFile.close(); |
return 1; |
|
} |
|
using_std_out = 0; |
|
} |
} |
else |
{ |
/* Input file */ |
if (!inFile.is_open()) |
{ |
inFile.open(argv[i], ios::in | ios::binary); |
if (!inFile.is_open()) |
{ |
cerr << "Error: unable to open file " << argv[1] << " for reading." << endl; |
return 1; |
} |
} |
|
} |
} |
|
|
/* First byte contains whether we've got register values included or |
just executed instruction, pc and number*/ |
inFile.seekg(0); /* Position getpointer to start of file*/ |
inFile.read(®_vals_included, 1); |
|
if (skip_insns) |
{ |
/* Position the file pointer to the right place before printing out */ |
if (skip_insns_from_end == -1) |
goto close_exit; |
if (skip_insns_from_end) |
{ |
|
// go to end |
inFile.seekg(0,ios::end); |
filesize = inFile.tellg(); |
inFile.seekg(0); |
//cout << "filesize: " << filesize << endl; |
// seek backwards |
if (reg_vals_included) |
for (int i=0;i<skip_insns;i++) |
inFile.seekg(filesize-skip_insns*sizeof(struct s_binary_output_buffer)); |
else |
for (int i=0;i<skip_insns;i++) |
inFile.seekg(filesize-(skip_insns*sizeof(struct s_binary_output_buffer_sans_regs))); |
|
} |
else |
{ |
// skip from start |
inFile.seekg(1); |
if (reg_vals_included) |
inFile.seekg(skip_insns*sizeof(struct s_binary_output_buffer),ios::cur); |
else |
inFile.seekg((skip_insns*sizeof(struct s_binary_output_buffer_sans_regs)),ios::cur); |
|
} |
} |
else |
inFile.seekg(1); |
|
//cout << "starting at: " << inFile.tellg() << endl; |
|
if (reg_vals_included) |
{ |
if (using_std_out) |
{ |
while (1) |
{ |
|
inFile.read((char*)&buf, sizeof(struct s_binary_output_buffer)); |
|
if(!inFile.eof()) |
{ |
cout << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << buf.insn_count << "): " << std::setfill('0') << hex << std::setw(8) << buf.pc << ": " << hex << std::setw(8) << buf.insn; |
if(buf.exception) cout << " (exception)"; |
cout << endl; |
|
// Print general purpose register contents |
for (int i=0; i<32; i++) |
{ |
if ((i%4 == 0)&&(i>0)) cout << endl; |
cout << std::setfill('0'); |
cout << "GPR" << dec << std::setw(2) << i << ": " << hex << std::setw(8) << buf.regs[i] << " "; |
} |
cout << endl; |
cout << "SR : " << hex << std::setw(8) << buf.sr << " "; |
cout << "EPCR0: " << hex << std::setw(8) << buf.epcr0 << " "; |
cout << "EEAR0: " << hex << std::setw(8) << buf.eear0 << " "; |
cout << "ESR0 : " << hex << std::setw(8) << buf.eser0 << endl; |
} |
else |
break; |
|
} |
} |
else |
{ |
while(1) |
{ |
/* Outputting to a file */ |
inFile.read((char*)&buf, sizeof(struct s_binary_output_buffer)); |
//inFile.seekg(sizeof(struct s_binary_output_buffer), ios::cur); |
if(!inFile.eof()) |
{ |
outFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << buf.insn_count << "): " << std::setfill('0') << hex << std::setw(8) << buf .pc << ": " << hex << std::setw(8) << buf.insn; |
if(buf.exception) outFile << " (exception)"; |
outFile << endl; |
|
// Print general purpose register contents |
for (int i=0; i<32; i++) |
{ |
if ((i%4 == 0)&&(i>0)) outFile << endl; |
outFile << std::setfill('0'); |
outFile << "GPR" << dec << std::setw(2) << i << ": " << hex << std::setw(8) << buf.regs[i] << " "; |
} |
outFile << endl; |
outFile << "SR : " << hex << std::setw(8) << buf.sr << " "; |
outFile << "EPCR0: " << hex << std::setw(8) << buf.epcr0 << " "; |
outFile << "EEAR0: " << hex << std::setw(8) << buf.eear0 << " "; |
outFile << "ESR0 : " << hex << std::setw(8) << buf.eser0 << endl; |
} |
else |
break; |
|
} |
} |
} |
else /* No regs in data */ |
{ |
if (using_std_out) |
{ |
while(1) |
{ |
inFile.read((char*)&buf_sans_regs, sizeof(struct s_binary_output_buffer_sans_regs)); |
if (!inFile.eof()) |
{ |
cout << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << buf_sans_regs.insn_count << "): " << std::setfill('0') << hex << std::setw(8) << buf_sans_regs.pc << ": " << hex << std::setw(8) << buf_sans_regs.insn; |
if(buf_sans_regs.exception) cout << " (exception)"; |
cout << endl; |
} |
else |
break; |
} |
cout << endl; |
} |
else |
{ |
/* Outputting to a file */ |
while(!inFile.eof()) |
{ |
inFile.read((char*)&buf_sans_regs, sizeof(struct s_binary_output_buffer_sans_regs)); |
//inFile.seekg(sizeof(struct s_binary_output_buffer_sans_regs), ios::cur); |
outFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << buf_sans_regs.insn_count << "): " << std::setfill('0') << hex << std::setw(8) << buf_sans_regs.pc << ": " << hex << std::setw(8) << buf_sans_regs.insn; |
if(buf_sans_regs.exception) outFile << " (exception)" << endl; |
outFile << endl; |
|
} |
outFile << endl; |
} |
} |
|
close_exit: |
inFile.close(); |
if (!using_std_out) outFile.close(); |
|
} |