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

Subversion Repositories openrisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/orpsocv2/bench/verilog
    from Rev 6 to Rev 40
    Reverse comparison

Rev 6 → Rev 40

/orpsoc_testbench.v
124,9 → 124,6
// Tie off some inputs
assign spi1_miso_i = 0;
assign uart0_srx_i = 1;
assign dbg_tdi_i = 1;
assign dbg_tck_i = 0;
assign dbg_tms_i = 1;
 
 
orpsoc_top dut
179,6 → 176,22
.rst_pad_i (rst_i),
.clk_pad_i (clk_i));
 
`ifdef VPI_DEBUG_ENABLE
// Debugging interface
vpi_debug_module vpi_dbg(
.tms(dbg_tms_i),
.tck(dbg_tck_i),
.tdi(dbg_tdi_i),
.tdo(dbg_tdo_o));
`else
// If no VPI debugging, tie off JTAG inputs
assign dbg_tdi_i = 1;
assign dbg_tck_i = 0;
assign dbg_tms_i = 1;
`endif
 
 
 
// External memories, if enabled
`ifdef USE_SDRAM
// SPI Flash
/vpi/c/rsp-rtl_sim.h
0,0 → 1,158
/*$$HEADER*/
/******************************************************************************/
/* */
/* H E A D E R I N F O R M A T I O N */
/* */
/******************************************************************************/
 
// Project Name : ORPSoCv2
// File Name : rsp-rtl_sim.h
// Prepared By : jb, jb@orsoc.se
// Project Start : 2009-05-01
 
/*$$COPYRIGHT NOTICE*/
/******************************************************************************/
/* */
/* C O P Y R I G H T N O T I C E */
/* */
/******************************************************************************/
/*
This library 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;
version 2.1 of the License, a copy of which is available from
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt.
 
This library 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 library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
 
#ifndef _RSP_RTL_SIM_H_
#define _RSP_RTL_SIM_H_
 
#include <stdint.h> // For uint32_t types
 
//#define DEBUG 1
//#define DEBUG2 1
 
#define Boolean int
#define false 0
#define true 1
 
#ifdef DEBUG
#define debug printf
#else
#define debug
#endif
 
#ifdef DEBUG2
#define debug2 printf
#else
#define debug2
#endif
 
 
#define DBG_ON 0
 
#define DBG_VPI 0
 
extern int vpi_to_rsp_pipe[2]; // [0] - read, [1] - write
extern int rsp_to_vpi_pipe[2]; // [0] - read, [1] - write
extern int command_pipe[2]; // RSP end writes, VPI end reads ONLY
 
#if (DEBUG) || (DEBUG2)
#define flush_debug() fflush(stdout)
#else
#define flush_debug()
#endif
 
# define JTAG_WAIT() usleep(1000)
# define JTAG_RETRY_WAIT() usleep (1000)
 
/* Selects crc trailer size in bits. Currently supported: 8 */
#define CRC_SIZE (8)
 
/* Scan chain size in bits. */
#define SC_SIZE (4)
 
/* function to kick off this server */
void run_rsp_server(int);
 
/* read a word from wishbone */
int dbg_wb_read32(uint32_t adr, uint32_t *data);
 
/* write a word to wishbone */
int dbg_wb_write32(uint32_t adr, uint32_t data);
 
/* read a block from wishbone */
int dbg_wb_read_block32(uint32_t adr, uint32_t *data, int len);
 
/* write a block to wishbone */
int dbg_wb_write_block32(uint32_t adr, uint32_t *data, int len);
 
/* read a register from cpu */
int dbg_cpu0_read(uint32_t adr, uint32_t *data);
 
/* read a register from cpu module */
int dbg_cpu0_read_ctrl(uint32_t adr, unsigned char *data);
 
/* write a cpu register */
int dbg_cpu0_write(uint32_t adr, uint32_t data);
 
/* write a cpu module register */
int dbg_cpu0_write_ctrl(uint32_t adr, unsigned char data);
 
/* send a message to the sim that the debugging client has disconnected */
void dbg_client_detached(void);
 
#define DC_SIZE 4
#define DC_STATUS_SIZE 4
 
#define DC_WISHBONE 0
#define DC_CPU0 1
#define DC_CPU1 2
 
#define DI_GO 0
#define DI_READ_CMD 1
#define DI_WRITE_CMD 2
#define DI_READ_CTRL 3
#define DI_WRITE_CTRL 4
 
#define DBG_CRC_SIZE 32
#define DBG_CRC_POLY 0x04c11db7
 
#define DBG_ERR_OK 0
#define DBG_ERR_CRC 8
 
#define NUM_SOFT_RETRIES 3
#define NUM_HARD_RETRIES 3
#define NUM_ACCESS_RETRIES 10
 
/* Possible errors are listed here. */
enum enum_errors /* modified <chris@asics.ws> CZ 24/05/01 */
{
/* Codes > 0 are for system errors */
 
ERR_NONE = 0,
ERR_CRC = -1,
ERR_MEM = -2,
JTAG_PROXY_INVALID_COMMAND = -3,
JTAG_PROXY_SERVER_TERMINATED = -4,
JTAG_PROXY_NO_CONNECTION = -5,
JTAG_PROXY_PROTOCOL_ERROR = -6,
JTAG_PROXY_COMMAND_NOT_IMPLEMENTED = -7,
JTAG_PROXY_INVALID_CHAIN = -8,
JTAG_PROXY_INVALID_ADDRESS = -9,
JTAG_PROXY_ACCESS_EXCEPTION = -10, /* Write to ROM */
JTAG_PROXY_INVALID_LENGTH = -11,
JTAG_PROXY_OUT_OF_MEMORY = -12,
};
 
#endif
 
/vpi/c/gdb.h
0,0 → 1,189
/*$$HEADER*/
/******************************************************************************/
/* */
/* H E A D E R I N F O R M A T I O N */
/* */
/******************************************************************************/
 
// Project Name : ORPSoCv2
// File Name : gdb.h
// Prepared By : jb, rmd
// Project Start : 2008-10-01
 
/*$$COPYRIGHT NOTICE*/
/******************************************************************************/
/* */
/* C O P Y R I G H T N O T I C E */
/* */
/******************************************************************************/
/*
This library 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;
version 2.1 of the License, a copy of which is available from
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt.
 
This library 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 library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
 
/*$$CHANGE HISTORY*/
/******************************************************************************/
/* */
/* C H A N G E H I S T O R Y */
/* */
/******************************************************************************/
 
// Date Version Description
//------------------------------------------------------------------------
// 081101 First revision, adapted from existing "jp"
// debug proxy. jb, rmd
// 090608 A few hacks for VPI compatibilty added jb
 
#ifndef GDB_H
#define GDB_H
 
#include <sys/types.h>
#include <inttypes.h>
 
extern void HandleServerSocket(void);
extern void handle_rsp (void);
int GetServerSocket(const char* name, const char* proto, int port);
extern void JTAGRequest(void);
void setup_or32(void);
void gdb_close();
void rsp_set_server_port(int);
 
//extern int err;
 
/* All JTAG chains. */
enum jtag_chains
{
SC_GLOBAL, /* 0 Global BS Chain */
SC_RISC_DEBUG, /* 1 RISC Debug Interface chain */
SC_RISC_TEST, /* 2 RISC Test Chain */
SC_TRACE, /* 3 Trace Chain */
SC_REGISTER, /* 4 Register Chain */
SC_WISHBONE, /* 5 Memory chain */
SC_BLOCK, /* 6 Block Chains */
};
 
/* See JTAG documentation about these. */
#define JI_SIZE (4)
enum jtag_instr
{
JI_EXTEST,
JI_SAMPLE_PRELOAD,
JI_IDCODE,
JI_CHAIN_SELECT,
JI_INTEST,
JI_CLAMP,
JI_CLAMPZ,
JI_HIGHZ,
JI_DEBUG,
JI_BYPASS = 0xF
};
 
/* JTAG registers. */
#define JTAG_MODER (0x0)
#define JTAG_TSEL (0x1)
#define JTAG_QSEL (0x2)
#define JTAG_SSEL (0x3)
#define JTAG_RISCOP (0x4)
#define JTAG_RECWP0 (0x10)
#define JTAG_RECBP0 (0x1b)
 
/* This is repeated from gdb tm-or1k.h There needs to be
a better mechanism for tracking this, but I don't see
an easy way to share files between modules. */
 
typedef enum {
JTAG_COMMAND_READ = 1,
JTAG_COMMAND_WRITE = 2,
JTAG_COMMAND_BLOCK_READ = 3,
JTAG_COMMAND_BLOCK_WRITE = 4,
JTAG_COMMAND_CHAIN = 5,
} JTAG_proxy_protocol_commands;
 
/* Each transmit structure must begin with an integer
which specifies the type of command. Information
after this is variable. Make sure to have all information
aligned properly. If we stick with 32 bit integers, it
should be portable onto every platform. These structures
will be transmitted across the network in network byte
order.
*/
 
typedef struct {
uint32_t command;
uint32_t length;
uint32_t address;
uint32_t data_H;
uint32_t data_L;
} JTAGProxyWriteMessage;
 
typedef struct {
uint32_t command;
uint32_t length;
uint32_t address;
} JTAGProxyReadMessage;
 
typedef struct {
uint32_t command;
uint32_t length;
uint32_t address;
int32_t nRegisters;
uint32_t data[1];
} JTAGProxyBlockWriteMessage;
 
typedef struct {
uint32_t command;
uint32_t length;
uint32_t address;
int32_t nRegisters;
} JTAGProxyBlockReadMessage;
 
typedef struct {
uint32_t command;
uint32_t length;
uint32_t chain;
} JTAGProxyChainMessage;
 
/* The responses are messages specific, however convention
states the first word should be an error code. Again,
sticking with 32 bit integers should provide maximum
portability. */
 
typedef struct {
int32_t status;
} JTAGProxyWriteResponse;
 
typedef struct {
int32_t status;
uint32_t data_H;
uint32_t data_L;
} JTAGProxyReadResponse;
typedef struct {
int32_t status;
} JTAGProxyBlockWriteResponse;
 
typedef struct {
int32_t status;
int32_t nRegisters;
uint32_t data[1];
/* uint32_t data[nRegisters-1] still unread */
} JTAGProxyBlockReadResponse;
 
typedef struct {
int32_t status;
} JTAGProxyChainResponse;
 
 
#endif /* GDB_H */
/vpi/c/rsp-vpi.h
0,0 → 1,74
/*$$HEADER*/
/******************************************************************************/
/* */
/* H E A D E R I N F O R M A T I O N */
/* */
/******************************************************************************/
 
// Project Name : ORPSoCv2
// File Name : rsp-vpi.h
// Prepared By : jb, jb@orsoc.se
// Project Start : 2009-05-01
 
/*$$COPYRIGHT NOTICE*/
/******************************************************************************/
/* */
/* C O P Y R I G H T N O T I C E */
/* */
/******************************************************************************/
/*
This library 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;
version 2.1 of the License, a copy of which is available from
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt.
 
This library 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 library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
 
// Defines for protocol ensuring synchronisation with the simulation process
 
// 1. rsp-rtl_sim will first write a command byte
// 2. rsp-rtl_sim will then send the address if it's a read or write
// or the data to write if it's a dbg_cpu_wr_ctrl (stall & reset bits)
// 3. will then send data if we're writing and we sent address in 2
// 4. wait for response from vpi functions
 
// commands:
// 4'h1 jtag set instruction register (input: instruction value)
// 4'h2 set debug chain (dbg_set_command here) (input: chain value)
// 4'h3 cpu_ctrl_wr (input: ctrl value (2 bits))
// 4'h4 cpu_ctrl_rd (output: ctrl value (2bits))
// 4'h5 cpu wr reg (inputs: address, data)
// 4'h6 cpu rd reg (input: address; output: data)
// 4'h7 wb wr 32 (inputs: address, data)
// 4'h8 wb rd 32 (input: address; output: data)
// 4'h9 wb wr block 32 (inputs: address, length, data)
// 4'ha wb rd block 32 (inputs: address, length; output: data)
// 4'hb reset
// 4'hc read jtag id (output: data)
// 4'hd GDB detach - do something (like close down, restart, etc.)
 
// There should be a correlating set of verilog `define's in the
// verilog debug testbench module's include file, test_defines.v
 
#define CMD_JTAG_SET_IR 0x1
#define CMD_SET_DEBUG_CHAIN 0x2
#define CMD_CPU_CTRL_WR 0x3
#define CMD_CPU_CTRL_RD 0x4
#define CMD_CPU_WR_REG 0x5
#define CMD_CPU_RD_REG 0x6
#define CMD_WB_WR32 0x7
#define CMD_WB_RD32 0x8
#define CMD_WB_BLOCK_WR32 0x9
#define CMD_WB_BLOCK_RD32 0xa
#define CMD_RESET 0xb
#define CMD_READ_JTAG_ID 0xc
#define CMD_GDB_DETACH 0xd
/vpi/c/jp_vpi.c
0,0 → 1,1064
/*$$HEADER*/
/******************************************************************************/
/* */
/* H E A D E R I N F O R M A T I O N */
/* */
/******************************************************************************/
 
// Project Name : ORPSoCv2
// File Name : jp_vpi.c
// Prepared By : jb, jb@orsoc.se
// Project Start : 2009-05-01
 
/*$$COPYRIGHT NOTICE*/
/******************************************************************************/
/* */
/* C O P Y R I G H T N O T I C E */
/* */
/******************************************************************************/
/*
This library 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;
version 2.1 of the License, a copy of which is available from
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt.
 
This library 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 library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
 
/*$$DESCRIPTION*/
/******************************************************************************/
/* */
/* D E S C R I P T I O N */
/* */
/******************************************************************************/
//
// Implements communication between verilog simulator and RSP server
//
//
/*
Functions used via the Verilog Procedural Interface (VPI), in a verilog
simulation of an OpenRISC processor, providing a means of communication to the
simulatin for a GDB stub.
 
The communication between the GDB stub and this module is via a "custom"
protocol, which is decoded into the verilog debug task module and the
appropriate transactions are performed with the debug interface inside the
OpenRISC design.
Operation:
See the verilog file containing the calls to the VPI tasks we outline in this
file for exact details of how they are used (debug_vpi_module.v), but
following is a brief outline of how it is meant to work.
 
The RSP GDB stub is initialised after compile via a VPI callback
(cbEndOfCompile). A process is forked off to run the RSP server, and IPC is via
pipes. Note: This is probably an extremely ineffecient way to do this as the
fork() creates a copy of the program, including it's ~200MB memory space, so
maybe a different method should be worked out for massive sims, but for smaller
OpenRISC designs on a power machine this is not a problem.
 
The verilog debug module polls for incoming commands from the GDB stub at a
#delay rate set in the verilog code.
 
The port which the GDB server runs on is #define'd in this file by
RSP_SERVER_PORT.
 
When a GDB connection is established, the state of the processor is downloaded
by GDB, so expect a slight delay after connection.
 
To close down the simulation gracefully, issue a "detach" command from GDB.
This will close the connection with the stub and will also send a message to
$finish the simulation.
 
Note: Simulation reset is untested, but should probably work OK.
 
Note: Reading uninitialised memory which returns Xs will break things.
Specifically, the CRC generation breaks, and then many other things. So to help
avoid hours of X tracing, ensure you're reading initialised space from GDB.
 
To Do:
* Comment this better! Sorry, it's a little lacking in this area.
* Block transfers (ie. what happens when "load"ing from GDB) ignore any bytes
over the word boundary at the end of a transfer. Currently a warning printf
will appear.
* Make the RSP server process not be a complete copy of the vvp image - ie.
don't fork() in the sim, maybe compile and exec() a separate app for this.
 
*/
 
 
/* EXAMPLE
// Associate C Function with a New System Task
voi
d registerHelloSystfs() {
s_vpi_systf_data task_data_s;
p_vpi_systf_data task_data_p = &task_data_s;
task_data_p->type = vpiSysTask;
task_data_p->tfname = "$hello";
task_data_p->calltf = hello;
task_data_p->compiletf = 0;
vpi_register_systf(task_data_p);
}
 
*/
 
 
/*
To associate your C function with a system task, create a
data structure of type s_vpi_systf_data and a pointer to
that structure. The vpi_systf_data data type is defined in
the vpi_user.h include file. Below is the data structure
of s_vpi_systf_data.
 
typedef struct t_vpi_systf_data {
PLI_INT32 type; // vpiSysTask, vpiSysFunc - task not return val, Func does
PLI_INT32 sysfunctype; // vpiSysTask, vpi[Int,Real,Time,Sized, SizedSigned]Func - if it's a func, this is the typ of return
PLI_BYTE8 *tfname; // First character must be `$'
PLI_INT32 (*calltf)(PLI_BYTE8 *); //pointer to the function
PLI_INT32 (*compiletf)(PLI_BYTE8 *); // pointer to a function that the simulator calls
// when it's compiled - can be NULL
PLI_INT32 (*sizetf)(PLI_BYTE8 *); // For sized function callbacks only, This field is a
// pointer to a routine that returns the size, in bits,
// of the value that the system task or function returns.
PLI_BYTE8 *user_data; --optional extra data?
} s_vpi_systf_data, *p_vpi_systf_data;
*/
 
 
 
/*$$CHANGE HISTORY*/
/******************************************************************************/
/* */
/* C H A N G E H I S T O R Y */
/* */
/******************************************************************************/
// Date Version Description
//------------------------------------------------------------------------
// 090501 Imported code from "jp" VPI project jb
// Changed to use pipes instead of sockets jb
 
 
 
 
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
#include <stdint.h>
#include <signal.h>
#include <inttypes.h>
 
// VPI includes
#include <vpi_user.h>
 
#ifdef CDS_VPI
// Cadence ncverilog specific include
#include <vpi_user_cds.h>
#endif
 
// Includes for the RSP server side of things
#include "gdb.h"
#include "rsp-rtl_sim.h"
#include "rsp-vpi.h"
 
// Define the port we open the RSP server on
#define RSP_SERVER_PORT 5555
 
//Function to register the function which sets up the sockets interface
void register_init_rsp_server_functions() ;
// Function which sets up the socket interface
void init_rsp_server();
//install a callback on simulation reset which calls setup
void setup_reset_callbacks();
//install a callback on simulation compilation finish
void setup_endofcompile_callbacks();
//install a callback on simulation finish
void setup_finish_callbacks();
//callback function which closes and clears the socket file descriptors
// on simulation reset
void sim_reset_callback();
void sim_endofcompile_callback();
void sim_finish_callback();
 
void register_check_for_command();
void register_get_command_address();
void register_get_command_data();
void register_return_command_block_data();
void register_return_command_data();
void register_get_command_block_data();
void register_return_response();
 
void check_for_command();
void get_command_address();
void get_command_data();
void get_command_block_data();
void return_command_data();
void return_command_block_data();
void return_response();
 
#include <time.h>
 
int vpi_to_rsp_pipe[2]; // [0] - read, [1] - write
int rsp_to_vpi_pipe[2]; // [0] - read, [1] - write
int command_pipe[2]; // RSP end writes, VPI end reads ONLY
 
/* Global static to store the child rsp server PID if we want to kill it */
static pid_t rsp_server_child_pid = (pid_t) 0; // pid_t is just a signed int
 
 
/********************************************************************/
/* init_rsp_server
*
* Fork off the rsp server process
* /
/********************************************************************/
void init_rsp_server(){
 
 
// First get the port number to start the RSP server on
vpiHandle systfref, args_iter, argh;
struct t_vpi_value argval;
 
int value,i;
 
int n;
 
int portNum;
char* send_buf;
 
/*
 
// Currently removed - ability to call $rsp_init_server() with a
// port number as parameter. Hardcoded allows us to run this as
// a callback after compiile (cbEndOfCompile)
 
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
 
// get a handle on the object passed to the function
argh = vpi_scan(args_iter);
 
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the data value
vpi_get_value(argh, &argval);
 
portNum = (int) argval.value.integer;
// Cleanup and return
vpi_free_object(args_iter);
// We should now have our port number.
 
*/
 
// Fork. Let the child run the RSP server
pid_t pid;
int rv;
 
if(DBG_ON) printf("jp_vpi: init_rsp_server\n");
 
// Setup pipes
if(pipe(vpi_to_rsp_pipe) == -1)
{
perror("jp_vpi: init_rsp_server pipes");
exit(1);
}
if(pipe(rsp_to_vpi_pipe) == -1)
{
perror("jp_vpi: init_rsp_server pipes");
exit(1);
}
if(pipe(command_pipe) == -1)
{
perror("jp_vpi: init_rsp_server pipes");
exit(1);
}
 
// Set command pipe to be non-blocking
#if defined (STRIDE) || (defined (pfa) && defined (HAVE_PTYS)) || defined (AIX)
{
int one = 1;
ioctl (command_pipe[0], FIONBIO, &one);
}
#endif
#ifdef O_NONBLOCK /* The POSIX way */
fcntl (command_pipe[0], F_SETFL, O_NONBLOCK);
#elif defined (O_NDELAY)
fcntl (command_pipe[0], F_SETFL, O_NDELAY);
#endif /* O_NONBLOCK */
// Check on the child process. If it has not been started it will
// be 0, else it will be something else and we'll just return
if ((int) rsp_server_child_pid > 0)
return;
 
switch(pid=fork())
{
case -1:
perror("fork");
exit(1);
break;
case 0: // Child
run_rsp_server(RSP_SERVER_PORT);
// exit if it ever returns, which it shouldn't
exit(0);
break;
default:
// We're the parent process, so continue on.
rsp_server_child_pid = pid;
break;
}
 
// Parent will only ever get this far...
 
return;
}
 
void register_init_rsp_server_functions() {
s_vpi_systf_data data = {vpiSysTask,
0,
"$init_rsp_server",
(void *)init_rsp_server,
0,
0,
0};
vpi_register_systf(&data);
return;
}
 
void print_command_string(unsigned char cmd)
{
switch(cmd)
{
case 0x1 :
printf(" TAP instruction register set\n");
break;
case 0x2 :
printf(" set debug chain\n");
break;
case 0x3 :
printf(" CPU control (stall/reset) reg write\n");
break;
case 0x4 :
printf(" CPU control (stall/reset) reg read\n");
break;
case 0x5 :
printf(" CPU reg write\n");
break;
case 0x6 :
printf(" CPU reg read\n");
break;
case 0x7 :
printf(" WB write 32\n");
break;
case 0x8 :
printf(" WB read 32\n");
break;
case 0x9 :
printf(" WB block write 32\n");
break;
case 0xa :
printf(" WB block read 32\n");
break;
case 0xb :
printf(" reset\n");
break;
case 0xc :
printf(" read jtag id\n");
break;
}
}
 
// See if there's anything on the FIFO for us
 
void check_for_command(char *userdata){
 
vpiHandle systfref, args_iter, argh;
 
struct t_vpi_value argval;
 
int value,i;
 
int n;
 
unsigned char data;
 
//if(DBG_ON) printf("check_for_command\n");
//n = read(rsp_to_vpi_pipe[0], &data, 1);
n = read(command_pipe[0], &data, 1);
 
if ( ((n < 0) && (errno == EAGAIN)) || (n==0) )
{
// Nothing in the fifo this time, let's return
return;
}
else if (n < 0)
{
// some sort of error
perror("check_for_command");
 
exit(1);
}
if (DBG_ON)
{
printf("jp_vpi: c = %x:",data);
print_command_string(data);
fflush(stdout);
}
// Return the command to the sim
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
 
// get a handle on the variable passed to the function
argh = vpi_scan(args_iter);
 
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the command value
vpi_get_value(argh, &argval);
 
argval.value.integer = (unsigned int) data;
 
// And vpi_put_value() it back into the sim
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
// Cleanup and return
vpi_free_object(args_iter);
 
n = write(vpi_to_rsp_pipe[1],&data,1);
if (DBG_ON) printf("jp_vpi: r");
 
if (DBG_ON) printf("\n");
return;
}
 
void get_command_address(char *userdata){
 
vpiHandle systfref, args_iter, argh;
 
struct t_vpi_value argval;
 
int value,i;
 
int n;
 
unsigned int data;
char* recv_buf;
 
recv_buf = (char *) &data; // cast data as our receive char buffer
 
n = read(rsp_to_vpi_pipe[0],recv_buf,4);
if (n<0)
{
//client has closed connection
//attempt to close and return gracefully
return;
}
if (DBG_ON) printf("jp_vpi: get_command_address adr=0x%.8x\n",data);
 
// now put the address into the argument passed to the task
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
 
// get a handle on the variable passed to the function
argh = vpi_scan(args_iter);
 
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the address value
vpi_get_value(argh, &argval);
argval.value.integer = (unsigned int) data;
// And vpi_put_value() it back into the sim
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
// Cleanup and return
vpi_free_object(args_iter);
return;
 
}
 
void get_command_data(char *userdata){
 
vpiHandle systfref, args_iter, argh;
 
struct t_vpi_value argval;
 
int value,i;
 
int n = 0;
 
unsigned int data;
char* recv_buf;
 
recv_buf = (char *) &data; // cast data as our receive char buffer
 
read_command_data_again:
n = read(rsp_to_vpi_pipe[0],recv_buf,4);
if ((n < 4) && errno==EAGAIN)
goto read_command_data_again;
else if (n < 4)
{
printf("jp_vpi: get_command_data errno: %d\n",errno);
perror("jp_vpi: get_command_data read failed");
}
if (DBG_ON) printf("jp_vpi: get_command_data = 0x%.8x\n",data);
 
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
 
// get a handle on the variable passed to the function
argh = vpi_scan(args_iter);
 
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the data value
vpi_get_value(argh, &argval);
argval.value.integer = (unsigned int) data;
// And vpi_put_value() it back into the sim
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
// Cleanup and return
vpi_free_object(args_iter);
return;
 
}
 
 
void get_command_block_data(){ // $get_command_block_data(length, mem_array)
 
vpiHandle systfref, args_iter, argh;
 
struct t_vpi_value argval;
 
int value,i;
 
int n;
 
unsigned int data;
unsigned int length;
 
char* recv_buf;
 
// Now setup the handles to verilog objects and check things
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
// get a handle on the length variable
argh = vpi_scan(args_iter);
argval.format = vpiIntVal;
// get the value for the length object
vpi_get_value(argh, &argval);
 
// now set length
length = argval.value.integer;
 
int num_words = length/4;
 
if((length % 4) != 0) vpi_printf("length of %d bytes is not exactly word-aligned\n",length);
// If non-word aligned we throw away remainder
int throw_away_bytes = length %4;
 
int loaded_words = 0;
 
if(DBG_ON)printf("jp_vpi: get_command_block_data: length=%d, num_words=%d\n",length,num_words);
 
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
 
// check we got passed a memory (array of regs)
if (vpi_get(vpiType, argh) != vpiMemory)
{
vpi_printf("jp_vpi: ERROR: did not pass a memory to get_command_block_data\n");
return;
}
// check the memory we're writing into is big enough
if (vpi_get(vpiSize, argh) < num_words )
{
vpi_printf("jp_vpi: ERROR: buffer passed to get_command_block_data too small. size is %d words, needs to be %d\n",
vpi_get(vpiSize, argh), num_words);
return;
}
vpiHandle array_word;
 
// Loop to load the words
while (loaded_words < num_words) {
recv_buf = (char *) &data;
// blocking receive for data block
n = read(rsp_to_vpi_pipe[0],recv_buf,4);
// now get a handle on the current word we want in the array that was passed to us
array_word = vpi_handle_by_index(argh, loaded_words);
if (array_word != NULL)
{
argval.value.integer = (unsigned int) data;
// And vpi_put_value() it back into the sim
vpi_put_value(array_word, &argval, NULL, vpiNoDelay);
}
else
return;
loaded_words++;
}
// TODO: This is a quick fix, should be delt with properly!!
if (throw_away_bytes)
{
//printf("reading off %d extra data bytes\n",throw_away_bytes);
n = read(rsp_to_vpi_pipe[0],&data,throw_away_bytes);
//printf("read off %d bytes \n",n);
}
// Cleanup and return
vpi_free_object(args_iter);
return;
 
}
 
void return_command_data(char *userdata){
 
vpiHandle systfref, args_iter, argh;
 
struct t_vpi_value argval;
 
int value,i;
 
int n;
 
uint32_t data;
char* send_buf;
 
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
 
// get a handle on the object passed to the function
argh = vpi_scan(args_iter);
 
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the data value
vpi_get_value(argh, &argval);
 
data = (unsigned int) argval.value.integer;
// Cleanup and return
vpi_free_object(args_iter);
 
if (DBG_ON) printf("jp_vpi: return_command_data 0x%.8x\n",data);
send_buf = (char *) &data; //cast our long as a char buf
// write the data back
n = write(vpi_to_rsp_pipe[1],send_buf,4);
 
return;
 
}
 
void return_command_block_data(){
 
vpiHandle systfref, args_iter, argh;
 
struct t_vpi_value argval;
 
int value,i;
 
int n;
 
unsigned int data;
unsigned int length;
 
char* recv_buf;
 
// Now setup the handles to verilog objects and check things
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
// get a handle on the length variable
argh = vpi_scan(args_iter);
argval.format = vpiIntVal;
// get the value for the length object
vpi_get_value(argh, &argval);
 
// now set length
length = argval.value.integer;
 
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
 
// check we got passed a memory (array of regs)
if (vpi_get(vpiType, argh) != vpiMemory)
{
vpi_printf("jp_vpi: ERROR: did not pass a memory to return_command_block_data\n");
return;
}
vpiHandle array_word;
int num_words = length/4;
int sent_words = 0;
// Loop to load the words
while (sent_words < num_words) {
// now get a handle on the current word we want in the array that was passed to us
array_word = vpi_handle_by_index(argh, sent_words);
if (array_word != NULL)
{
vpi_get_value(array_word, &argval);
data = (unsigned int) argval.value.integer;
}
else
return;
 
recv_buf = (char *) &data;
n = write(vpi_to_rsp_pipe[1],recv_buf,4);
sent_words++;
}
// Cleanup and return
vpi_free_object(args_iter);
return;
 
}
 
 
 
void return_response(char *userdata){
 
int n;
char resp = 0;
// send a response byte
n = write(vpi_to_rsp_pipe[1],&resp,1);
if (DBG_ON) printf("jp_vpi: ret\n\n");
return;
 
}
 
void register_check_for_command() {
s_vpi_systf_data data = {vpiSysTask,
0,
"$check_for_command",
(void *)check_for_command,
0,
0,
0};
 
vpi_register_systf(&data);
 
return;
}
 
void register_get_command_address() {
s_vpi_systf_data data = {vpiSysTask,
0,
"$get_command_address",
(void *)get_command_address,
0,
0,
0};
 
vpi_register_systf(&data);
 
return;
}
 
void register_get_command_data() {
s_vpi_systf_data data = {vpiSysTask,
0,
"$get_command_data",
(void *)get_command_data,
0,
0,
0};
 
vpi_register_systf(&data);
 
return;
}
 
void register_get_command_block_data() {
s_vpi_systf_data data = {vpiSysTask,
0,
"$get_command_block_data",
(void *)get_command_block_data,
0,
0,
0};
 
vpi_register_systf(&data);
 
return;
}
 
 
void register_return_command_block_data() {
s_vpi_systf_data data = {vpiSysTask,
0,
"$return_command_block_data",
(void *)return_command_block_data,
0,
0,
0};
 
vpi_register_systf(&data);
 
return;
}
 
void register_return_command_data() {
s_vpi_systf_data data = {vpiSysTask,
0,
"$return_command_data",
(void *)return_command_data,
0,
0,
0};
 
vpi_register_systf(&data);
 
return;
}
 
void register_return_response() {
s_vpi_systf_data data = {vpiSysTask,
0,
"$return_response",
(void *)return_response,
0,
0,
0};
 
vpi_register_systf(&data);
 
return;
}
 
 
void setup_reset_callbacks()
{
// here we setup and install callbacks for
// the setup and management of connections to
// the simulator upon simulation start and
// reset
 
static s_vpi_time time_s = {vpiScaledRealTime};
static s_vpi_value value_s = {vpiBinStrVal};
static s_cb_data cb_data_s =
{
cbEndOfReset, // or start of simulation - initing socket fds etc
(void *)sim_reset_callback,
NULL,
&time_s,
&value_s
};
cb_data_s.obj = NULL; /* trigger object */
 
cb_data_s.user_data = NULL;
 
// actual call to register the callback
vpi_register_cb(&cb_data_s);
 
}
 
void sim_reset_callback()
{
 
// nothing to do!
 
return;
 
}
 
void setup_endofcompile_callbacks()
{
// here we setup and install callbacks for
// simulation finish
 
static s_vpi_time time_s = {vpiScaledRealTime};
static s_vpi_value value_s = {vpiBinStrVal};
static s_cb_data cb_data_s =
{
cbEndOfCompile, // end of compile
(void *)sim_endofcompile_callback,
NULL,
&time_s,
&value_s
};
cb_data_s.obj = NULL; /* trigger object */
 
cb_data_s.user_data = NULL;
 
// actual call to register the callback
vpi_register_cb(&cb_data_s);
 
}
 
void sim_endofcompile_callback()
{
// Init the RSP server
init_rsp_server(); // Start the RSP server from here!
 
}
 
 
void setup_finish_callbacks()
{
// here we setup and install callbacks for
// simulation finish
 
static s_vpi_time time_s = {vpiScaledRealTime};
static s_vpi_value value_s = {vpiBinStrVal};
static s_cb_data cb_data_s =
{
cbEndOfSimulation, // end of simulation
(void *)sim_finish_callback,
NULL,
&time_s,
&value_s
};
cb_data_s.obj = NULL; /* trigger object */
 
cb_data_s.user_data = NULL;
 
// actual call to register the callback
vpi_register_cb(&cb_data_s);
 
}
 
void sim_finish_callback()
{
printf("Closing RSP server\n");
// Close down the child process, if it hasn't already
kill(rsp_server_child_pid,SIGTERM);
}
 
 
 
// Register the new system task here
void (*vlog_startup_routines[ ] ) () = {
register_init_rsp_server_functions,
#ifdef CDS_VPI
// this installs a callback on simulator reset - something which
// icarus does not do, so we only do it for cadence currently
setup_reset_callbacks,
#endif
setup_endofcompile_callbacks,
setup_finish_callbacks,
register_check_for_command,
register_get_command_address,
register_get_command_data,
register_get_command_block_data,
register_return_command_data,
register_return_command_block_data,
register_return_response,
0 // last entry must be 0
};
 
 
 
// Entry point for testing development of the vpi functions
int main(int argc, char *argv[])
{
 
return 0;
}
 
 
 
/vpi/c/rsp-rtl_sim.c
0,0 → 1,605
/*$$HEADER*/
/******************************************************************************/
/* */
/* H E A D E R I N F O R M A T I O N */
/* */
/******************************************************************************/
 
// Project Name : ORPSoCv2
// File Name : rsp-rtl_sim.c
// Prepared By : jb, jb@orsoc.se
// Project Start : 2009-05-01
 
/*$$COPYRIGHT NOTICE*/
/******************************************************************************/
/* */
/* C O P Y R I G H T N O T I C E */
/* */
/******************************************************************************/
/*
This library 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;
version 2.1 of the License, a copy of which is available from
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt.
 
This library 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 library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
 
 
/* Establishes GDB proxy server and communicates via pipes
to some functions running under the VPI in an RTL sim */
 
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
 
#include <ctype.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
 
#include "gdb.h"
#include "rsp-rtl_sim.h"
#include "rsp-vpi.h"
 
static int err = 0;
 
/* Currently selected scan chain - just to prevent unnecessary
transfers. */
static int current_chain = -1;
 
/* The chain that should be currently selected. */
static int dbg_chain = -1;
 
/* Crc of current read or written data. */
static int crc_r, crc_w = 0;
 
/* Generates new crc, sending in new bit input_bit */
static uint32_t crc_calc(uint32_t crc, int input_bit) {
uint32_t d = (input_bit&1) ? 0xfffffff : 0x0000000;
uint32_t crc_32 = ((crc >> 31)&1) ? 0xfffffff : 0x0000000;
crc <<= 1;
return crc ^ (d ^ crc_32) & DBG_CRC_POLY;
}
 
/* VPI communication prototyopes */
static void get_response_from_vpi();
static void get_data_from_vpi();
static void get_block_data_from_vpi(int len, uint32_t *data);
static void send_data_to_vpi(uint32_t data);
static void send_block_data_to_vpi(int len, uint32_t *data);
static void send_address_to_vpi(uint32_t address);
static void send_command_to_vpi(char CMD);
 
void send_command_to_vpi(char CMD)
{
// first thing we do is send a command
// and wait for an ack
int n;
char cmd_resp;
//n = write(rsp_to_vpi_pipe[1],&CMD, 1); // send the command to the sim
n = write(command_pipe[1],&CMD, 1); // send the command to the sim
if (n < 0) error("ERROR writing to VPI FIFO");
n = read(vpi_to_rsp_pipe[0],&cmd_resp,1); // block and wait for the ack
if (cmd_resp != CMD) error("Response from RTL sim incorrect"); //check it acked with cmd
 
return;
}
 
void send_address_to_vpi(uint32_t address)
{
// Now send address
int n;
 
char* send_buf;
 
send_buf = (char *) &address;
n = write(rsp_to_vpi_pipe[1],send_buf, 4); // send the address to the sim
if (n < 0) error("ERROR writing to VPI socket");
return;
}
 
void send_data_to_vpi(uint32_t data)
{
// Now send data
int n;
 
char* send_buf;
 
send_buf = (char *) &data;
n = write(rsp_to_vpi_pipe[1],send_buf, 4); // Write the data to the socket
if (n < 0) error("ERROR writing to VPI socket");
return;
}
 
void send_block_data_to_vpi(int len, uint32_t *data)
{
// Now send data
int n, i;
char* send_buf;
send_buf = (char *) data;
n = write(rsp_to_vpi_pipe[1],send_buf, len); // Write the data to the fifo
if (n < 0) error("ERROR writing to VPI socket");
return;
}
 
void get_data_from_vpi(uint32_t* data)
{
int n;
uint32_t inc_data;
char* recv_buf;
recv_buf = (char*) &inc_data;
n = read(vpi_to_rsp_pipe[0],recv_buf,4); // block and wait for the data
 
if (DBG_VPI) printf("rsp-rtl_sim: get_data_from_vpi: 0x%.8x\n",inc_data);
 
*data = inc_data;
return;
 
}
 
void get_block_data_from_vpi(int len, uint32_t* data)
{
int n, i, status;
uint32_t inc_data;
char* recv_buf;
 
uint32_t* data_ptr;
recv_buf = (char *) data;
 
n=0;
 
while (n < len)
{
status = read(vpi_to_rsp_pipe[0], recv_buf, len - n); // block and wait for the data
if (status > 0) n += status; // we read "status" number of bytes
}
 
 
if (DBG_VPI){
printf("rsp-rtl_sim: get_block_data_from_vpi: %d bytes",len);
for (i = 0;i < (len/4); i++)
{
printf("0x%.8x ",data[i]);
}
printf("\n");
}
return;
 
}
 
void get_response_from_vpi()
{
// Basically just wait for the response from VPI
// by blocking wait on recv
int n = 0;
char tmp;
 
n = read(vpi_to_rsp_pipe[0],&tmp,1); // block and wait
return;
}
 
/* Resets JTAG
Writes TRST=0
and TRST=1 */
static void jp2_reset_JTAG() {
int i;
 
debug2("\nreset(");
 
send_command_to_vpi(CMD_RESET);
 
get_response_from_vpi();
debug2(")\n");
 
}
 
/* Resets JTAG, and sets DEBUG scan chain */
int dbg_reset() {
int err;
uint32_t id;
jp2_reset_JTAG();
 
/* set idcode jtag chain */
send_command_to_vpi(CMD_JTAG_SET_IR);
 
send_data_to_vpi(JI_IDCODE);
 
get_response_from_vpi();
 
/* now read out the jtag id */
send_command_to_vpi(CMD_READ_JTAG_ID);
//id = get_data_from_vpi();
get_data_from_vpi((uint32_t *)&id);
get_response_from_vpi();
printf("JTAG ID = %08x\n", id);
 
/* now set the chain to debug */
send_command_to_vpi(CMD_JTAG_SET_IR);
send_data_to_vpi(JI_DEBUG);
get_response_from_vpi();
 
current_chain = -1;
return DBG_ERR_OK;
}
 
/* counts retries and returns zero if we should abort */
/* TODO: dinamically adjust timings for jp2 */
static int retry_no = 0;
int retry_do() {
int i, err;
printf("RETRY\n");
//exit(2);
if (retry_no >= NUM_SOFT_RETRIES) {
if ((err = dbg_reset())) return err;
}
if (retry_no >= NUM_SOFT_RETRIES + NUM_HARD_RETRIES) {
retry_no = 0;
return 0;
}
retry_no++;
return 1;
}
 
/* resets retry counter */
void retry_ok() {
retry_no = 0;
}
 
/* Sets scan chain. */
int dbg_set_chain(int chain) {
 
debug("\n");
debug2("dbg_set_chain %d\n", chain);
if (current_chain == chain)
return DBG_ERR_OK;
dbg_chain = chain;
send_command_to_vpi(CMD_SET_DEBUG_CHAIN);
send_data_to_vpi(chain);
get_response_from_vpi();
current_chain = chain;
return DBG_ERR_OK;
}
 
/* writes a ctrl reg */
int dbg_ctrl(int reset, int stall)
{
debug("\n");
debug2("ctrl\n");
dbg_set_chain(dbg_chain);
send_command_to_vpi(CMD_CPU_CTRL_WR);
//send_data_to_vpi(((reset & 0x1) | ((stall&0x1)<<1)));
send_data_to_vpi(((stall & 0x1) | ((reset&0x1)<<1)));
get_response_from_vpi();
 
return DBG_ERR_OK;
}
 
/* reads control register */
int dbg_ctrl_read(int *reset, int *stall)
{
uint32_t resp;
dbg_set_chain(dbg_chain);
debug("\n");
debug2("ctrl\n");
dbg_set_chain(dbg_chain);
send_command_to_vpi(CMD_CPU_CTRL_RD);
get_data_from_vpi((uint32_t *)&resp);
if (DBG_VPI) printf("rsp-rtl_sim: dbg_ctrl_read: 0x%.8x\n",resp);
 
get_response_from_vpi();
*reset = (int)(resp & 0x00000001);
 
*stall = (int)((resp >> 1) & 0x00000001);
return DBG_ERR_OK;
}
 
/* read a word from wishbone */
int dbg_wb_read32(uint32_t adr, uint32_t *data)
{
//uint32_t resp;
 
dbg_set_chain(DC_WISHBONE);
send_command_to_vpi(CMD_WB_RD32);
send_address_to_vpi(adr);
get_data_from_vpi(data);
get_response_from_vpi();
return 0;
}
 
/* write a word to wishbone */
int dbg_wb_write32(uint32_t adr, uint32_t data)
{
 
dbg_set_chain(DC_WISHBONE);
send_command_to_vpi(CMD_WB_WR32);
send_address_to_vpi(adr);
 
send_data_to_vpi(data);
get_response_from_vpi();
return 0;
}
 
/* read a block from wishbone */
int dbg_wb_read_block32(uint32_t adr, uint32_t *data, int len)
{
// len is in B Y T E S ! !
 
if (DBG_VPI) printf("rsp-rtl_sim: block read len: %d from addr: 0x%.8x\n",len, adr);
 
dbg_set_chain(DC_WISHBONE);
send_command_to_vpi(CMD_WB_BLOCK_RD32);
 
send_data_to_vpi(adr);
 
send_data_to_vpi(len);
 
get_block_data_from_vpi(len, data);
 
get_response_from_vpi();
return DBG_ERR_OK;
}
 
/* write a block to wishbone */
int dbg_wb_write_block32(uint32_t adr, uint32_t *data, int len)
{
dbg_set_chain(DC_WISHBONE);
send_command_to_vpi(CMD_WB_BLOCK_WR32);
 
send_data_to_vpi(adr);
send_data_to_vpi(len);
 
send_block_data_to_vpi(len, data);
 
get_response_from_vpi();
 
return DBG_ERR_OK;
}
 
/* read a register from cpu */
int dbg_cpu0_read(uint32_t adr, uint32_t *data)
{
dbg_set_chain(DC_CPU0);
send_command_to_vpi(CMD_CPU_RD_REG);
send_address_to_vpi(adr);
get_data_from_vpi(data);
get_response_from_vpi();
return 0;
 
}
 
/* write a cpu register */
int dbg_cpu0_write(uint32_t adr, uint32_t data)
{
 
uint32_t resp;
dbg_set_chain(DC_CPU0);
send_command_to_vpi(CMD_CPU_WR_REG);
send_address_to_vpi(adr);
send_data_to_vpi(data);
get_response_from_vpi();
return 0;
}
 
/* read a register from cpu */
int dbg_cpu1_read(uint32_t adr, uint32_t *data) {
/*
int err;
if ((err = dbg_set_chain(DC_CPU1))) return err;
if ((err = dbg_command(0x6, adr, 4))) return err;
if ((err = dbg_go((unsigned char*)data, 4, 1))) return err;
*data = ntohl(*data);
*/
return DBG_ERR_OK;
}
 
/* write a cpu register */
int dbg_cpu1_write(uint32_t adr, uint32_t data) {
/*
int err;
data = ntohl(data);
if ((err = dbg_set_chain(DC_CPU1))) return err;
if ((err = dbg_command(0x2, adr, 4))) return err;
if ((err = dbg_go((unsigned char*)&data, 4, 0))) return err;
*/
return DBG_ERR_OK;
}
 
/* read a register from cpu module */
int dbg_cpu1_read_ctrl(uint32_t adr, unsigned char *data) {
/*
int err;
int r, s;
if ((err = dbg_set_chain(DC_CPU1))) return err;
if ((err = dbg_ctrl_read(&r, &s))) return err;
*data = (r << 1) | s;
*/
return DBG_ERR_OK;
}
 
/* write a cpu module register */
int dbg_cpu0_write_ctrl(uint32_t adr, unsigned char data) {
int err;
if ((err = dbg_set_chain(DC_CPU0))) return err;
if ((err = dbg_ctrl(data & 2, data &1))) return err;
return DBG_ERR_OK;
}
 
/* read a register from cpu module */
int dbg_cpu0_read_ctrl(uint32_t adr, unsigned char *data) {
int err;
int r, s;
if ((err = dbg_set_chain(DC_CPU0))) return err;
if ((err = dbg_ctrl_read(&r, &s))) return err;
*data = (r << 1) | s;
return DBG_ERR_OK;
}
 
void dbg_test() {
int i;
uint32_t npc, ppc, r1, insn, result;
unsigned char stalled;
// uint32_t stalled;
unsigned char read_byte;
 
printf(" Stall or1k\n");
dbg_cpu0_write_ctrl(0, 0x01); // stall or1k
 
dbg_cpu0_read_ctrl(0, &stalled);
if (!(stalled & 0x1)) {
printf("\tor1k stall failed. read: 0x%x\n", stalled); // check stall or1k
//exit(1);
}
debug2(" Reading npc\n");
dbg_cpu0_read((0 << 11) + 16, &npc);
debug2(" Reading ppc\n");
dbg_cpu0_read((0 << 11) + 18, &ppc);
debug2(" Reading r1\n");
dbg_cpu0_read(0x401, &r1);
printf(" Read npc = %.8x ppc = %.8x r1 = %.8x\n", npc, ppc, r1);
}
 
// Catch the term/int signals, close gdb then close ourselves
void catch_sigint(int sig_num)
{
gdb_close();
exit(0);
}
 
void dbg_client_detached(void)
{
// Send this message back to the sim
send_command_to_vpi(CMD_GDB_DETACH);
}
 
 
// This function is called after the fork in the VPI function.
 
void run_rsp_server(int portNum)
{
// Send commands to init and reset debug interface
dbg_reset();
// Stall and read NPC, PPC etc
dbg_test();
set_rsp_server_port(portNum);
 
// Install SIGINT/SIGTERM handlers, to close down gracefully
signal(SIGINT, catch_sigint);
signal(SIGTERM, catch_sigint);
 
if (DBG_ON) printf("rsp-rtl_sim: starting handle_rsp()\n");
// Now, start the RSP server. This should not return
handle_rsp ();
// Exit gracefully if it returns (shouldn't though)
exit(0);
 
}
 
 
/vpi/c/Makefile
0,0 → 1,54
######################################################################
#### ####
#### VPI Makefile ####
#### ####
#### Description ####
#### Makefile for VPI libraries ####
#### ####
#### To Do: ####
#### Add compatability for other simulators (Cadence, etc.) ####
#### ####
#### Author(s): ####
#### - jb, jb@orsoc.se ####
#### ####
#### ####
######################################################################
#### ####
#### Copyright (C) 2009 Authors and OPENCORES.ORG ####
#### ####
#### This source file may be used and distributed without ####
#### restriction provided that this copyright statement is not ####
#### removed from the file and that any derivative work contains ####
#### the original copyright notice and the associated disclaimer. ####
#### ####
#### This source file 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 2.1 of the License, or (at your option) any ####
#### later version. ####
#### ####
#### This source 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 source; if not, download it ####
#### from http://www.opencores.org/lgpl.shtml ####
#### ####
######################################################################
 
SOURCE_FILES= jp_vpi.c rsp-rtl_sim.c gdb.c
 
# Uncomment this line to enable debugging of all VPI code
 
#DEBUG_DEFINES=-DDEBUG -DDEBUG2 -DDEBUG_ON=1 -DDEBUG_GDB=1 -DDEBUG_CMDS=1
 
all: jp_vpi
 
jp_vpi: $(SOURCE_FILES)
iverilog-vpi $(SOURCE_FILES) $(DEBUG_DEFINES)
 
clean:
rm -f *.o *~ jp_vpi.vpi
/vpi/c/gdb.c
0,0 → 1,4093
/*$$HEADER*/
/******************************************************************************/
/* */
/* H E A D E R I N F O R M A T I O N */
/* */
/******************************************************************************/
 
// Project Name : ORPSoCv2
// File Name : gdb.c
// Prepared By : jb, rmd
// Project Start : 2008-10-01
 
/*$$COPYRIGHT NOTICE*/
/******************************************************************************/
/* */
/* C O P Y R I G H T N O T I C E */
/* */
/******************************************************************************/
/*
This library 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;
version 2.1 of the License, a copy of which is available from
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt.
 
This library 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 library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
 
/*$$DESCRIPTION*/
/******************************************************************************/
/* */
/* D E S C R I P T I O N */
/* */
/******************************************************************************/
//
// Implements RSP comatible GDB stub
//
 
 
/*$$CHANGE HISTORY*/
/******************************************************************************/
/* */
/* C H A N G E H I S T O R Y */
/* */
/******************************************************************************/
 
// Date Version Description
//------------------------------------------------------------------------
// 081101 Imported code from "jp" project jb
// 090219 Adapted code from Jeremy Bennett's RSP server
// for the or1ksim project. rmb
// 090304 Finished RSP server code import, added extra
// functions, adding stability when debugging on
// a remote target. jb
// 090608 A few hacks for VPI compatibilty added jb
 
#ifdef CYGWIN_COMPILE
 
#else
// linux includes
#include <time.h>
#include <sched.h>
#endif
 
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
 
/* Libraries for JTAG proxy server. */
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <inttypes.h>
#include <errno.h>
#include <arpa/inet.h>
 
 
#ifndef DEBUG_GDB
#define DEBUG_GDB 0
#endif
 
#ifndef DEBUG_GDB_DUMP_DATA
#define DEBUG_GDB_DUMP_DATA 0
#endif
 
#ifndef DEBUG_GDB_BLOCK_DATA
#define DEBUG_GDB_BLOCK_DATA 0
#endif
 
#ifndef DEBUG_CMDS
#define DEBUG_CMDS 0
#endif
 
/*! Name of the Or1ksim RSP service */
#define OR1KSIM_RSP_SERVICE "or1ksim-rsp"
 
#include "gdb.h" /* partially copied from gdb/config/or1k */
#include "rsp-rtl_sim.h"
 
#define MAX_GPRS (32)
 
/* Indices of GDB registers that are not GPRs. Must match GDB settings! */
#define PPC_REGNUM (MAX_GPRS + 0) /*!< Previous PC */
#define NPC_REGNUM (MAX_GPRS + 1) /*!< Next PC */
#define SR_REGNUM (MAX_GPRS + 2) /*!< Supervision Register */
#define NUM_REGS (MAX_GPRS + 3) /*!< Total GDB registers */
 
/* OR1k CPU registers address */
#define NPC_CPU_REG_ADD 0x10 /* Next PC */
#define SR_CPU_REG_ADD 0x11 /* Supervision Register */
#define PPC_CPU_REG_ADD 0x12 /* Previous PC */
#define DMR1_CPU_REG_ADD ((6 << 11) + 16) /* Debug Mode Register 1 (DMR1) 0x3010 */
#define DMR2_CPU_REG_ADD ((6 << 11) + 17) /* Debug Mode Register 2 (DMR2) 0x3011 */
#define DSR_CPU_REG_ADD ((6 << 11) + 20) /* Debug Stop Register (DSR) 0x3014 */
#define DRR_CPU_REG_ADD ((6 << 11) + 21) /* Debug Reason Register (DRR) 0x3015 */
 
/*! Trap instruction for OR32 */
#define OR1K_TRAP_INSTR 0x21000001
 
/*! The maximum number of characters in inbound/outbound buffers. The largest
packets are the 'G' packet, which must hold the 'G' and all the registers
with two hex digits per byte and the 'g' reply, which must hold all the
registers, and (in our implementation) an end-of-string (0)
character. Adding the EOS allows us to print out the packet as a
string. So at least NUMREGBYTES*2 + 1 (for the 'G' or the EOS) are needed
for register packets */
#define GDB_BUF_MAX ((NUM_REGS) * 8 + 1)
 
/*! Size of the matchpoint hash table. Largest prime < 2^10 */
#define MP_HASH_SIZE 1021
 
/* Definition of special-purpose registers (SPRs). */
#define MAX_SPRS (0x10000)
 
#define SPR_DMR1_ST 0x00400000 /* Single-step trace*/
#define SPR_DMR2_WGB 0x003ff000 /* Watchpoints generating breakpoint */
#define SPR_DSR_TE 0x00002000 /* Trap exception */
 
#define WORDSBIGENDIAN_N
 
/* Definition of OR1K exceptions */
#define EXCEPT_NONE 0x0000
#define EXCEPT_RESET 0x0100
#define EXCEPT_BUSERR 0x0200
#define EXCEPT_DPF 0x0300
#define EXCEPT_IPF 0x0400
#define EXCEPT_TICK 0x0500
#define EXCEPT_ALIGN 0x0600
#define EXCEPT_ILLEGAL 0x0700
#define EXCEPT_INT 0x0800
#define EXCEPT_DTLBMISS 0x0900
#define EXCEPT_ITLBMISS 0x0a00
#define EXCEPT_RANGE 0x0b00
#define EXCEPT_SYSCALL 0x0c00
#define EXCEPT_FPE 0x0d00
#define EXCEPT_TRAP 0x0e00
 
// Changed to #defines from static const int's due to compile error
// DRR (Debug Reason Register) Bits
#define SPR_DRR_RSTE 0x00000001 //!< Reset
#define SPR_DRR_BUSEE 0x00000002 //!< Bus error
#define SPR_DRR_DPFE 0x00000004 //!< Data page fault
#define SPR_DRR_IPFE 0x00000008 //!< Insn page fault
#define SPR_DRR_TTE 0x00000010 //!< Tick timer
#define SPR_DRR_AE 0x00000020 //!< Alignment
#define SPR_DRR_IIE 0x00000040 //!< Illegal instruction
#define SPR_DRR_IE 0x00000080 //!< Interrupt
#define SPR_DRR_DME 0x00000100 //!< DTLB miss
#define SPR_DRR_IME 0x00000200 //!< ITLB miss
#define SPR_DRR_RE 0x00000400 //!< Range fault
#define SPR_DRR_SCE 0x00000800 //!< System call
#define SPR_DRR_FPE 0x00001000 //!< Floating point
#define SPR_DRR_TE 0x00002000 //!< Trap
 
 
/*! Definition of GDB target signals. Data taken from the GDB 6.8
source. Only those we use defined here. The exact meaning of
signal number is defined by the header `include/gdb/signals.h'
in the GDB source code. For an explanation of what each signal
means, see target_signal_to_string.*/
enum target_signal {
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
};
 
/*! String to map hex digits to chars */
static const char hexchars[]="0123456789abcdef";
 
 
//! Is the NPC cached?
 
//! 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),
//! so we must cache the NPC. As soon as the processor is unstalled, this
//! cached value becomes invalid. So we must track the stall state, and if
//! appropriate cache the NPC.
enum stallStates {
STALLED,
UNSTALLED,
UNKNOWN
} stallState;
 
int npcIsCached; //!< Is the NPC cached - should be bool
uint32_t npcCachedValue; //!< Cached value of the NPC
 
static int err = 0;
 
 
/************************
JTAG Server Routines
************************/
int serverIP = 0;
int serverPort = 0;
int server_fd = 0;
int gdb_fd = 0;
 
static int tcp_level = 0;
 
/* global to store what chain the debug unit is currently connected to
(not the JTAG TAP, but the onchip debug module has selected) */
int gdb_chain = -1;
 
/*! Data structure for RSP buffers. Can't be null terminated, since it may
include zero bytes */
struct rsp_buf
{
char data[GDB_BUF_MAX];
int len;
};
 
/*! Enumeration of different types of matchpoint. These have explicit values
matching the second digit of 'z' and 'Z' packets. */
enum mp_type {
BP_MEMORY = 0, // software-breakpoint Z0 break
BP_HARDWARE = 1, // hardware-breakpoint Z1 hbreak
WP_WRITE = 2, // write-watchpoint Z2 watch
WP_READ = 3, // read-watchpoint Z3 rwatch
WP_ACCESS = 4 // access-watchpoint Z4 awatch
};
 
/*! Data structure for a matchpoint hash table entry */
struct mp_entry
{
enum mp_type type; /*!< Type of matchpoint */
uint32_t addr; /*!< Address with the matchpoint */
uint32_t instr; /*!< Substituted instruction */
struct mp_entry *next; /*!< Next entry with this hash */
};
 
/*! Central data for the RSP connection */
static struct
{
int client_waiting; /*!< Is client waiting a response? */
// Not used int proto_num; /*!< Number of the protocol used */
int client_fd; /*!< FD for talking to GDB */
int sigval; /*!< GDB signal for any exception */
uint32_t start_addr; /*!< Start of last run */
struct mp_entry *mp_hash[MP_HASH_SIZE]; /*!< Matchpoint hash table */
} rsp;
 
/* Forward declarations of static functions */
static char *printTime(void);
static int gdb_read(void*, int);
static int gdb_write(void*, int);
static void ProtocolClean(int, int32_t);
static void GDBRequest(void);
static void rsp_interrupt();
static char rsp_peek();
static struct rsp_buf *get_packet (void);
static void rsp_init (void);
static void set_npc (uint32_t addr);
static uint32_t get_npc();
static void rsp_check_for_exception();
static int check_for_exception_vector(uint32_t ppc);
static void rsp_exception (uint32_t except);
static int get_rsp_char (void);
static int hex (int c);
static void rsp_get_client (void);
static void rsp_client_request (void);
static void rsp_client_close (void);
static void client_close (char err);
static void put_str_packet (const char *str);
static void rsp_report_exception (void);
static void put_packet (struct rsp_buf *p_buf);
static void send_rsp_str (unsigned char *data, int len);
static void rsp_query (struct rsp_buf *p_buf);
static void rsp_vpkt (struct rsp_buf *p_buf);
static void rsp_step (struct rsp_buf *p_buf);
static void rsp_step_with_signal (struct rsp_buf *p_buf);
static void rsp_step_generic (uint32_t addr, uint32_t except);
static void rsp_continue (struct rsp_buf *p_buf);
static void rsp_continue_with_signal (struct rsp_buf *p_buf);
static void rsp_continue_generic (uint32_t addr, uint32_t except);
static void rsp_read_all_regs (void);
static void rsp_write_all_regs (struct rsp_buf *p_buf);
static void rsp_read_mem (struct rsp_buf *p_buf);
static void rsp_write_mem (struct rsp_buf *p_buf);
static void rsp_write_mem_bin (struct rsp_buf *p_buf);
static int rsp_unescape (char *data, int len);
static void rsp_read_reg (struct rsp_buf *p_buf);
static void rsp_write_reg (struct rsp_buf *p_buf);
static void mp_hash_init (void);
static void mp_hash_add (enum mp_type type, uint32_t addr, uint32_t instr);
static struct mp_entry * mp_hash_lookup (enum mp_type type, uint32_t addr);
static struct mp_entry * mp_hash_delete (enum mp_type type, uint32_t addr);
static void rsp_remove_matchpoint (struct rsp_buf *p_buf);
static void rsp_insert_matchpoint (struct rsp_buf *p_buf);
static void rsp_command (struct rsp_buf *p_buf);
static void rsp_set (struct rsp_buf *p_buf);
static void rsp_restart (void);
static void ascii2hex (char *dest,char *src);
static void hex2ascii (char *dest, char *src);
static uint32_t hex2reg (char *p_buf);
static void reg2hex (uint32_t val, char *p_buf);
static void swap_buf(char* p_buf, int len);
static void set_stall_state (int state);
static void reset_or1k (void);
static void gdb_ensure_or1k_stalled();
static int gdb_set_chain(int chain);
static int gdb_write_reg(uint32_t adr, uint32_t data);
static int gdb_read_reg(uint32_t adr, uint32_t *data);
static int gdb_write_block(uint32_t adr, uint32_t *data, int len);
static int gdb_read_block(uint32_t adr, uint32_t *data, int len);
 
char *printTime(void)
{
time_t tid;
struct tm *strtm;
static char timeBuf[20];
time(&tid);
strtm = localtime(&tid);
sprintf(timeBuf,"[%.02d:%.02d:%.02d] ",strtm->tm_hour,strtm->tm_min,strtm->tm_sec);
return timeBuf;
}
/*---------------------------------------------------------------------------*/
/*!Set the serverPort variable
*/
/*---------------------------------------------------------------------------*/
 
void
set_rsp_server_port(int portNum)
{
serverPort = portNum;
}
 
/*---------------------------------------------------------------------------*/
/*!Initialize the Remote Serial Protocol connection
 
Set up the central data structures. */
/*---------------------------------------------------------------------------*/
void
rsp_init (void)
{
/* Clear out the central data structure */
rsp.client_waiting = 0; /* GDB client is not waiting for us */
rsp.client_fd = -1; /* i.e. invalid */
rsp.sigval = 0; /* No exception */
rsp.start_addr = EXCEPT_RESET; /* Default restart point */
 
/* Set up the matchpoint hash table */
mp_hash_init ();
/* RSP always starts stalled as though we have just reset the processor. */
rsp_exception (EXCEPT_TRAP);
 
/* Setup the NPC caching variables */
stallState = STALLED;
// Force a caching of the NPC
npcIsCached = 0;
get_npc();
} /* rsp_init () */
 
/*---------------------------------------------------------------------------*/
/*!Look for action on RSP
 
This function is called when the processor has stalled, which, except for
initialization, must be due to an interrupt.
 
If we have no RSP client, we get one. We can make no progress until the
client is available.
 
Then if the cause is an exception following a step or continue command, and
the exception not been notified to GDB, a packet reporting the cause of the
exception is sent.
 
The next client request is then processed. */
/*---------------------------------------------------------------------------*/
void
handle_rsp (void)
{
uint32_t temp_uint32;
 
rsp_init();
while (1){
/* If we have no RSP client, wait until we get one. */
while (-1 == rsp.client_fd)
{
rsp_get_client ();
rsp.client_waiting = 0; /* No longer waiting */
}
/* If we have an unacknowledged exception tell the GDB client. If this
exception was a trap due to a memory breakpoint, then adjust the NPC. */
if (rsp.client_waiting)
{
// Check for exception
rsp_check_for_exception();
if(stallState == STALLED)
// Get the PPC if we're stalled
gdb_read_reg(PPC_CPU_REG_ADD, &temp_uint32);
if ((TARGET_SIGNAL_TRAP == rsp.sigval) && (NULL != mp_hash_lookup (BP_MEMORY, temp_uint32)))
{
if (stallState != STALLED)
// This is a quick fix for a strange situation seen in some of the simulators where
// the sw bp would be detected, but the stalled state variable wasn't updated correctly
// indicating that last time it checked, it wasn't set but the processor has now hit the
// breakpoint. So run rsp_check_for_exception() to bring everything up to date.
rsp_check_for_exception();
if(DEBUG_GDB) printf("Software breakpoint hit at 0x%08x. Rolling back NPC to this instruction\n", temp_uint32);
set_npc (temp_uint32);
rsp_report_exception();
rsp.client_waiting = 0; /* No longer waiting */
}
else if(stallState == STALLED) {
// If we're here, the thing has stalled, but not because of a breakpoint we set
// report back the exception
rsp_report_exception();
rsp.client_waiting = 0; /* No longer waiting */
}
}
// See if there's any incoming data from the client by peeking at the socket
if (rsp_peek() > 0)
{
if (rsp_peek() == 0x03 && (stallState != STALLED)) // 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
rsp_interrupt();
rsp.client_waiting = 0;
}
else if (rsp.client_waiting == 0)
{
// Default handling of data from the client:
/* Get a RSP client request */
rsp_client_request ();
}
} /* end if (rsp_peek() > 0) */
}
 
} /* handle_rsp () */
 
 
/*
Check if processor is stalled - if it is, read the DRR
and return the target signal code
*/
static void rsp_check_for_exception()
{
 
unsigned char stalled;
uint32_t drr;
err = dbg_cpu0_read_ctrl(0, &stalled); /* check if we're stalled */
if (!(stalled & 0x01))
{
// Processor not stalled. Just return;
return;
}
if (DEBUG_GDB) printf("rsp_check_for_exception() detected processor was stalled\nChecking DRR\n");
// We're stalled
stallState = STALLED;
npcIsCached = 0;
 
gdb_set_chain(SC_RISC_DEBUG);
 
// Now read the DRR (Debug Reason Register)
gdb_read_reg(DRR_CPU_REG_ADD, &drr);
 
if (DEBUG_GDB) printf("DRR: 0x%08x\n", drr);
switch ((int)(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;
}
 
if (DEBUG_GDB) printf("rsp.sigval: 0x%x\n", rsp.sigval);
return;
}
 
/*---------------------------------------------------------------------------*/
/*!Check if PPC is in an exception vector that halts program flow
 
Compare the provided PPC with known exception vectors that are fatal
to a program's execution. Call rsp_exception(ppc) to set the appropriate
sigval and return.
 
@param[in] ppc Value of current PPC, as read from debug unit
@return: 1 if we set a sigval and should return control to GDB, else 0 */
/*---------------------------------------------------------------------------*/
static int
check_for_exception_vector(uint32_t ppc)
{
switch(ppc)
{
// The following should return sigvals to GDB for processing
case EXCEPT_BUSERR:
case EXCEPT_ALIGN:
case EXCEPT_ILLEGAL:
case EXCEPT_TRAP: if(DEBUG_GDB)
printf("PPC at exception address\n");
rsp_exception(ppc);
return 1;
default:
return 0;
}
return 1;
}
 
/*---------------------------------------------------------------------------*/
/*!Note an exception for future processing
 
The simulator has encountered an exception. Record it here, so that a
future call to handle_exception will report it back to the client. The
signal is supplied in Or1ksim form and recorded in GDB form.
 
We flag up a warning if an exception is already pending, and ignore the
earlier exception.
 
@param[in] except The exception (Or1ksim form) */
/*---------------------------------------------------------------------------*/
void
rsp_exception (uint32_t except)
{
int sigval; /* GDB signal equivalent to exception */
 
switch (except)
{
case EXCEPT_RESET: sigval = TARGET_SIGNAL_PWR; break;
case EXCEPT_BUSERR: sigval = TARGET_SIGNAL_BUS; break;
case EXCEPT_DPF: sigval = TARGET_SIGNAL_SEGV; break;
case EXCEPT_IPF: sigval = TARGET_SIGNAL_SEGV; break;
case EXCEPT_TICK: sigval = TARGET_SIGNAL_ALRM; break;
case EXCEPT_ALIGN: sigval = TARGET_SIGNAL_BUS; break;
case EXCEPT_ILLEGAL: sigval = TARGET_SIGNAL_ILL; break;
case EXCEPT_INT: sigval = TARGET_SIGNAL_INT; break;
case EXCEPT_DTLBMISS: sigval = TARGET_SIGNAL_SEGV; break;
case EXCEPT_ITLBMISS: sigval = TARGET_SIGNAL_SEGV; break;
case EXCEPT_RANGE: sigval = TARGET_SIGNAL_FPE; break;
case EXCEPT_SYSCALL: sigval = TARGET_SIGNAL_USR2; break;
case EXCEPT_FPE: sigval = TARGET_SIGNAL_FPE; break;
case EXCEPT_TRAP: sigval = TARGET_SIGNAL_TRAP; break;
 
default:
fprintf (stderr, "Warning: Unknown RSP exception %u: Ignored\n", except);
return;
}
 
if ((0 != rsp.sigval) && (sigval != rsp.sigval))
{
fprintf (stderr, "Warning: RSP signal %d received while signal "
"%d pending: Pending exception replaced\n", sigval, rsp.sigval);
}
 
rsp.sigval = sigval; /* Save the signal value */
 
} /* rsp_exception () */
 
 
/*---------------------------------------------------------------------------*/
/*!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.
 
The protocol used for communication is specified in OR1KSIM_RSP_PROTOCOL. */
/*---------------------------------------------------------------------------*/
static void
rsp_get_client (void)
{
int tmp_fd; /* Temporary descriptor for socket */
int optval; /* Socket options */
struct sockaddr_in sock_addr; /* Socket address */
socklen_t len; /* Size of the socket address */
 
/* 0 is used as the RSP port number to indicate that we should use the
service name instead. */
if (0 == serverPort)
{
struct servent *service = getservbyname (OR1KSIM_RSP_SERVICE, "tcp");
if (NULL == service)
{
fprintf (stderr, "Warning: RSP unable to find service \"%s\": %s \n",
OR1KSIM_RSP_SERVICE, strerror (errno));
return;
}
serverPort = ntohs (service->s_port);
}
 
/* Open a socket on which we'll listen for clients */
tmp_fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (tmp_fd < 0)
{
fprintf (stderr, "ERROR: Cannot open RSP socket\n");
exit (0);
}
 
/* Allow rapid reuse of the port on this socket */
optval = 1;
setsockopt (tmp_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval,
sizeof (optval));
 
/* Bind the port to the socket */
sock_addr.sin_family = PF_INET;
sock_addr.sin_port = htons (serverPort);
sock_addr.sin_addr.s_addr = INADDR_ANY;
if (bind (tmp_fd, (struct sockaddr *) &sock_addr, sizeof (sock_addr)))
{
fprintf (stderr, "ERROR: Cannot bind to RSP socket\n");
exit (0);
}
/* Listen for (at most one) client */
if (0 != listen (tmp_fd, 1))
{
fprintf (stderr, "ERROR: Cannot listen on RSP socket\n");
exit (0);
}
 
printf("Waiting for gdb connection on localhost:%d\n", serverPort);
fflush (stdout);
 
printf("Press CTRL+c and type 'finish' to exit.\n");
fflush (stdout);
 
/* Accept a client which connects */
len = sizeof (sock_addr);
rsp.client_fd = accept (tmp_fd, (struct sockaddr *)&sock_addr, &len);
 
if (-1 == rsp.client_fd)
{
fprintf (stderr, "Warning: Failed to accept RSP client\n");
return;
}
 
/* Enable TCP keep alive process */
optval = 1;
setsockopt (rsp.client_fd, 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(rsp.client_fd, F_GETFL, 0)))
flags = 0;
fcntl(rsp.client_fd, F_SETFL, flags | O_NONBLOCK);
#else
/* Otherwise, use the old way of doing it */
flags = 1;
ioctl(fd, 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 instnatly 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, rsp_peek() has been implemented to simply check if
there's an incoming command from GDB (only interested in interrupt
commands), otherwise it returns back to and poll the processor's PPC and
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(rsp.client_fd, FIONBIO, (char *)&optval) > 0 )
{
perror("ioctl() failed");
close(rsp.client_fd);
close(tmp_fd);
exit(0);
}
 
/* Don't delay small packets, for better interactive response (disable
Nagel's algorithm) */
optval = 1;
setsockopt (rsp.client_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&optval,
sizeof (optval));
 
/* Socket is no longer needed */
close (tmp_fd); /* No longer need this */
signal (SIGPIPE, SIG_IGN); /* So we don't exit if client dies */
 
printf ("Remote debugging from host %s\n", inet_ntoa (sock_addr.sin_addr));
} /* rsp_get_client () */
 
 
/*---------------------------------------------------------------------------*/
/*!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. */
/*---------------------------------------------------------------------------*/
static void rsp_client_request (void)
{
struct rsp_buf *p_buf = get_packet (); /* Message sent to us */
 
// Null packet means we hit EOF or the link was closed for some other
// reason. Close the client and return
if (NULL == p_buf)
{
rsp_client_close ();
return;
}
 
if (DEBUG_GDB){
printf("%s-----------------------------------------------------\n", printTime());
printf ("Packet received %s: %d chars\n", p_buf->data, p_buf->len );
fflush (stdout);
}
 
switch (p_buf->data[0])
{
case '!':
/* Request for extended remote mode */
put_str_packet ("OK"); // OK = supports and has enabled extended mode.
return;
 
case '?':
/* Return last signal ID */
rsp_report_exception();
return;
 
case 'A':
/* Initialization of argv not supported */
fprintf (stderr, "Warning: RSP 'A' packet not supported: ignored\n");
put_str_packet ("E01");
return;
 
case 'b':
/* Setting baud rate is deprecated */
fprintf (stderr, "Warning: RSP 'b' packet is deprecated and not "
"supported: ignored\n");
return;
 
case 'B':
/* Breakpoints should be set using Z packets */
fprintf (stderr, "Warning: RSP 'B' packet is deprecated (use 'Z'/'z' "
"packets instead): ignored\n");
return;
 
case 'c':
/* Continue */
rsp_continue (p_buf);
return;
 
case 'C':
/* Continue with signal */
rsp_continue_with_signal (p_buf);
return;
 
case 'd':
/* Disable debug using a general query */
fprintf (stderr, "Warning: RSP 'd' packet is deprecated (define a 'Q' "
"packet instead: ignored\n");
return;
 
case 'D':
/* Detach GDB. Do this by closing the client. The rules say that
execution should continue. TODO. Is this really then intended
meaning? Or does it just mean that only vAttach will be recognized
after this? */
put_str_packet ("OK");
// In VPI disconnect everyone and exit
rsp_client_close();
client_close('0');
dbg_client_detached(); // Send message to sim that the client detached
exit(0);
//reset_or1k ();
//set_stall_state (0);
return;
 
case 'F':
/* File I/O is not currently supported */
fprintf (stderr, "Warning: RSP file I/O not currently supported: 'F' "
"packet ignored\n");
return;
 
case 'g':
rsp_read_all_regs ();
return;
 
case 'G':
rsp_write_all_regs (p_buf);
return;
case 'H':
/* Set the thread number of subsequent operations. For now ignore
silently and just reply "OK" */
put_str_packet ("OK");
return;
 
case 'i':
/* Single instruction step */
fprintf (stderr, "Warning: RSP cycle stepping not supported: target "
"stopped immediately\n");
rsp.client_waiting = 1; /* Stop reply will be sent */
return;
 
case 'I':
/* Single instruction step with signal */
fprintf (stderr, "Warning: RSP cycle stepping not supported: target "
"stopped immediately\n");
rsp.client_waiting = 1; /* Stop reply will be sent */
return;
 
case 'k':
/* Kill request. Do nothing for now. */
return;
 
case 'm':
/* Read memory (symbolic) */
rsp_read_mem (p_buf);
return;
 
case 'M':
/* Write memory (symbolic) */
rsp_write_mem (p_buf);
return;
 
case 'p':
/* Read a register */
rsp_read_reg (p_buf);
return;
 
case 'P':
/* Write a register */
rsp_write_reg (p_buf);
return;
 
case 'q':
/* Any one of a number of query packets */
rsp_query (p_buf);
return;
 
case 'Q':
/* Any one of a number of set packets */
rsp_set (p_buf);
return;
 
case 'r':
/* Reset the system. Deprecated (use 'R' instead) */
fprintf (stderr, "Warning: RSP 'r' packet is deprecated (use 'R' "
"packet instead): ignored\n");
return;
 
case 'R':
/* Restart the program being debugged. */
rsp_restart ();
return;
 
case 's':
/* Single step (one high level instruction). This could be hard without
DWARF2 info */
rsp_step (p_buf);
return;
 
case 'S':
/* Single step (one high level instruction) with signal. This could be
hard without DWARF2 info */
rsp_step_with_signal (p_buf);
return;
 
case 't':
/* Search. This is not well defined in the manual and for now we don't
support it. No response is defined. */
fprintf (stderr, "Warning: RSP 't' packet not supported: ignored\n");
return;
 
case 'T':
/* Is the thread alive. We are bare metal, so don't have a thread
context. The answer is always "OK". */
put_str_packet ("OK");
return;
 
case 'v':
/* Any one of a number of packets to control execution */
rsp_vpkt (p_buf);
return;
 
case 'X':
/* Write memory (binary) */
rsp_write_mem_bin (p_buf);
return;
 
case 'z':
/* Remove a breakpoint/watchpoint. */
rsp_remove_matchpoint (p_buf);
return;
 
case 'Z':
/* Insert a breakpoint/watchpoint. */
rsp_insert_matchpoint (p_buf);
return;
 
default:
/* Unknown commands are ignored */
fprintf (stderr, "Warning: Unknown RSP request %s\n", p_buf->data);
return;
}
} /* rsp_client_request () */
 
 
/*---------------------------------------------------------------------------*/
/*!Close the connection to the client if it is open */
/*---------------------------------------------------------------------------*/
static void
rsp_client_close (void)
{
if (-1 != rsp.client_fd)
{
close (rsp.client_fd);
rsp.client_fd = -1;
}
} /* rsp_client_close () */
 
 
/*---------------------------------------------------------------------------*/
/*!Send a packet to the GDB client
 
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.
 
@param[in] p_buf The data to send */
/*---------------------------------------------------------------------------*/
static void
put_packet (struct rsp_buf *p_buf)
{
unsigned char data[GDB_BUF_MAX * 2];
int len;
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 (DEBUG_GDB_DUMP_DATA){
printf ("Putting %s\n\n", p_buf->data);
fflush (stdout);
}
 
len = 0;
data[len++] = '$'; /* Start char */
 
/* Body of the packet */
for (count = 0; count < p_buf->len; count++)
{
unsigned char ch = p_buf->data[count];
 
/* Check for escaped chars */
if (('$' == ch) || ('#' == ch) || ('*' == ch) || ('}' == ch))
{
ch ^= 0x20;
checksum += (unsigned char)'}';
data[len++] = '}';
}
 
checksum += ch;
data[len++] = ch;
}
 
data[len++] = '#'; /* End char */
 
/* Computed checksum */
data[len++] = (hexchars[checksum >> 4]);
data[len++] = (hexchars[checksum % 16]);
 
send_rsp_str ((unsigned char *) &data, len);
 
/* Check for ack of connection failure */
ch = get_rsp_char ();
if (0 > ch)
{
return; /* Fail the put silently. */
}
}
while ('+' != ch);
} /* put_packet () */
 
 
/*---------------------------------------------------------------------------*/
/*!Convenience to put a constant string packet
 
param[in] str The text of the packet */
/*---------------------------------------------------------------------------*/
static void
put_str_packet (const char *str)
{
struct rsp_buf buffer;
int len = 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 (len >= GDB_BUF_MAX)
{
fprintf (stderr, "Warning: String %s too large for RSP packet: "
"truncated\n", str);
len = GDB_BUF_MAX - 1;
}
 
strncpy (buffer.data, str, len);
buffer.data[len] = 0;
buffer.len = len;
 
put_packet (&buffer);
 
} /* put_str_packet () */
 
 
/*---------------------------------------------------------------------------*/
/*!Get a packet from the GDB client
Modeled on the stub version supplied with GDB. The data is in a static
buffer. The data should be copied elsewhere if it is to be preserved across
a subsequent call to get_packet().
 
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.
 
@return A pointer to the static buffer containing the data */
/*---------------------------------------------------------------------------*/
static struct rsp_buf *
get_packet (void)
{
static struct rsp_buf buf; /* Survives the return */
 
/* Keep getting packets, until one is found with a valid checksum */
while (1)
{
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 = get_rsp_char ();
 
while (ch != '$')
{
if (-1 == ch)
{
return NULL; /* Connection failed */
}
 
ch = get_rsp_char ();
 
// Potentially handle an interrupt character (0x03) here
}
 
/* Read until a '#' or end of buffer is found */
checksum = 0;
count = 0;
while (count < GDB_BUF_MAX - 1)
{
ch = get_rsp_char ();
if(rsp.client_waiting && DEBUG_GDB)
{
printf("%x\n",ch);
}
 
 
/* Check for connection failure */
if (0 > ch)
{
return NULL;
}
 
/* 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;
buf.data[count] = (char)ch;
count = count + 1;
}
 
/* Mark the end of the buffer with EOS - it's convenient for non-binary
data to be valid strings. */
buf.data[count] = 0;
buf.len = count;
 
/* If we have a valid end of packet char, validate the checksum */
if ('#' == ch)
{
unsigned char xmitcsum; /* The checksum in the packet */
 
ch = get_rsp_char ();
if (0 > ch)
{
return NULL; /* Connection failed */
}
xmitcsum = hex (ch) << 4;
 
ch = get_rsp_char ();
if (0 > ch)
{
return NULL; /* Connection failed */
}
 
xmitcsum += hex (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)
{
fprintf (stderr, "Warning: Bad RSP checksum: Computed "
"0x%02x, received 0x%02x\n", checksum, xmitcsum);
 
ch = '-';
send_rsp_str ((unsigned char *) &ch, 1); /* Failed checksum */
}
else
{
ch = '+';
send_rsp_str ((unsigned char *) &ch, 1); /* successful transfer */
break;
}
}
else
{
fprintf (stderr, "Warning: RSP packet overran buffer\n");
}
}
return &buf; /* Success */
} /* get_packet () */
 
 
/*---------------------------------------------------------------------------*/
/*!Put a single character out onto the client socket
 
This should only be called if the client is open, but we check for safety.
 
@param[in] c The character to put out */
/*---------------------------------------------------------------------------*/
static void
send_rsp_str (unsigned char *data, int len)
{
if (-1 == rsp.client_fd)
{
fprintf (stderr, "Warning: Attempt to write '%s' to unopened RSP "
"client: Ignored\n", data);
return;
}
 
/* Write until successful (we retry after interrupts) or catastrophic
failure. */
while (1)
{
switch (write (rsp.client_fd, data, len))
{
case -1:
/* Error: only allow interrupts or would block */
if ((EAGAIN != errno) && (EINTR != errno))
{
fprintf (stderr, "Warning: Failed to write to RSP client: "
"Closing client connection: %s\n",
strerror (errno));
rsp_client_close ();
return;
}
break;
 
case 0:
break; /* Nothing written! Try again */
 
default:
return; /* Success, we can return */
}
}
} /* send_rsp_str () */
 
 
/*---------------------------------------------------------------------------*/
/*!Get a single character from the client socket
 
This should only be called if the client is open, but we check for safety.
 
@return The character read, or -1 on failure */
/*---------------------------------------------------------------------------*/
static int
get_rsp_char ()
{
if (-1 == rsp.client_fd)
{
fprintf (stderr, "Warning: Attempt to read from unopened RSP "
"client: Ignored\n");
return -1;
}
 
/* Non-blocking read until successful (we retry after interrupts) or
catastrophic failure. */
while (1)
{
unsigned char c;
 
switch (read (rsp.client_fd, &c, sizeof (c)))
{
case -1:
/* Error: only allow interrupts */
if ((EAGAIN != errno) && (EINTR != errno))
{
fprintf (stderr, "Warning: Failed to read from RSP client: "
"Closing client connection: %s\n",
strerror (errno));
rsp_client_close ();
return -1;
}
 
break;
 
case 0:
// EOF
rsp_client_close ();
return -1;
 
default:
return c & 0xff; /* Success, we can return (no sign extend!) */
}
}
} /* get_rsp_char () */
 
/*---------------------------------------------------------------------------*/
/* !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 */
/*---------------------------------------------------------------------------*/
static char
rsp_peek()
{
/*
if (-1 == rsp.client_fd)
{
fprintf (stderr, "Warning: Attempt to read from unopened RSP "
"client: Ignored\n");
return -1;
}
*/
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 (rsp.client_fd, &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 '\0';
 
}
 
/*---------------------------------------------------------------------------*/
/*!Handle an interrupt from GDB
 
Detect an interrupt from GDB and stall the processor */
/*---------------------------------------------------------------------------*/
static void
rsp_interrupt()
{
unsigned char c;
 
if (read (rsp.client_fd, &c, sizeof (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)
{
printf("Warning: Interrupt character expected but not found on socket.\n");
return;
}
// Otherwise, it's an interrupt packet, stall the processor, and upon return
// to the main handle_rsp() loop, it will inform GDB.
 
if (DEBUG_GDB) printf("Interrupt received from GDB. Stalling processor.\n");
 
set_stall_state (1);
 
// Send a stop reply response, manually set rsp.sigval to TARGET_SIGNAL_NONE
rsp.sigval = TARGET_SIGNAL_NONE;
rsp_report_exception();
rsp.client_waiting = 0; /* No longer waiting */
 
return;
}
 
 
/*---------------------------------------------------------------------------*/
/*!"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] data The array of bytes to convert
@para[in] len The number of bytes to be converted
 
@return The number of bytes AFTER conversion */
/*---------------------------------------------------------------------------*/
static int
rsp_unescape (char *data,
int len)
{
int from_off = 0; /* Offset to source char */
int to_off = 0; /* Offset to dest char */
 
while (from_off < len)
{
/* Is it escaped */
if ( '}' == data[from_off])
{
from_off++;
data[to_off] = data[from_off] ^ 0x20;
}
else
{
data[to_off] = data[from_off];
}
 
from_off++;
to_off++;
}
 
return to_off;
 
} /* rsp_unescape () */
 
 
/*---------------------------------------------------------------------------*/
/*!Initialize the matchpoint hash table
 
This is an open hash table, so this function clears all the links to
NULL. */
/*---------------------------------------------------------------------------*/
static void
mp_hash_init (void)
{
int i;
 
for (i = 0; i < MP_HASH_SIZE; i++)
{
rsp.mp_hash[i] = NULL;
}
} /* mp_hash_init () */
 
 
/*---------------------------------------------------------------------------*/
/*!Add an entry to the matchpoint 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.
 
@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 */
/*---------------------------------------------------------------------------*/
static void
mp_hash_add (enum mp_type type,
uint32_t addr,
uint32_t instr)
{
int hv = addr % MP_HASH_SIZE;
struct mp_entry *curr;
 
/* See if we already have the entry */
for(curr = rsp.mp_hash[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 = (struct mp_entry*) malloc (sizeof (*curr));
 
curr->type = type;
curr->addr = addr;
curr->instr = instr;
curr->next = rsp.mp_hash[hv];
 
rsp.mp_hash[hv] = curr;
 
} /* mp_hash_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 deleted, or NULL if the entry was not found */
/*---------------------------------------------------------------------------*/
static struct mp_entry * mp_hash_lookup (enum mp_type type, uint32_t addr)
{
int hv = addr % MP_HASH_SIZE;
struct mp_entry *curr;
 
/* Search */
for (curr = rsp.mp_hash[hv]; NULL != curr; curr = curr->next)
{
if ((type == curr->type) && (addr == curr->addr))
{
return curr; /* The entry found */
}
}
 
/* Not found */
return NULL;
} /* mp_hash_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 usual fun and games tracking the previous entry, so we can delete
things.
 
@note The deletion DOES NOT free the memory associated with the entry,
since that is returned. The caller should free the memory when they
have used the information.
 
@param[in] type The type of matchpoint
@param[in] addr The address of the matchpoint
 
@return The entry deleted, or NULL if the entry was not found */
/*---------------------------------------------------------------------------*/
static struct mp_entry *
mp_hash_delete (enum mp_type type,
uint32_t addr)
{
int hv = addr % MP_HASH_SIZE;
struct mp_entry *prev = NULL;
struct mp_entry *curr;
 
/* Search */
for (curr = rsp.mp_hash[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)
{
rsp.mp_hash[hv] = curr->next;
}
else
{
prev->next = curr->next;
}
 
return curr; /* The entry deleted */
}
 
prev = curr;
}
 
/* Not found */
return NULL;
} /* mp_hash_delete () */
 
 
/*---------------------------------------------------------------------------*/
/*!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. */
/*---------------------------------------------------------------------------*/
static int hex (int c)
{
return ((c >= 'a') && (c <= 'f')) ? c - 'a' + 10 :
((c >= '0') && (c <= '9')) ? c - '0' :
((c >= 'A') && (c <= 'F')) ? c - 'A' + 10 : -1;
 
} /* hex () */
 
 
/*---------------------------------------------------------------------------*/
/*!Convert a register to a hex digit string
 
The supplied 32-bit value is converted to an 8 digit hex string according
the target endianism. It is null terminated for convenient printing.
 
@param[in] val The value to convert
@param[out] p_buf The buffer for the text string */
/*---------------------------------------------------------------------------*/
static void
reg2hex (uint32_t val, char *p_buf)
{
int n; /* Counter for digits */
int nyb_shift;
 
for (n = 0; n < 8; n++)
{
#ifdef WORDSBIGENDIAN
if(n%2==0){
nyb_shift = n * 4 + 4;
}
else{
nyb_shift = n * 4 - 4;
}
#else
nyb_shift = 28 - (n * 4);
#endif
p_buf[n] = hexchars[(val >> nyb_shift) & 0xf];
}
 
p_buf[8] = 0; /* Useful to terminate as string */
 
} /* reg2hex () */
 
 
/*---------------------------------------------------------------------------*/
/*!Convert a hex digit string to a register value
 
The supplied 8 digit hex string is converted to a 32-bit value according
the target endianism
 
@param[in] p_buf The buffer with the hex string
 
@return The value to convert */
/*---------------------------------------------------------------------------*/
static uint32_t
hex2reg (char *p_buf)
{
int n; /* Counter for digits */
uint32_t val = 0; /* The result */
 
for (n = 0; n < 8; n++)
{
#ifdef WORDSBIGENDIAN
int nyb_shift = n * 4;
#else
int nyb_shift = 28 - (n * 4);
#endif
val |= hex (p_buf[n]) << nyb_shift;
}
 
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) */
/*---------------------------------------------------------------------------*/
static void 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] = hexchars[ch >> 4 & 0xf];
dest[i * 2 + 1] = hexchars[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) */
/*---------------------------------------------------------------------------*/
static void 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] = ((hex (src[i * 2]) & 0xf) << 4) | (hex (src[i * 2 + 1]) & 0xf);
}
 
dest[i] = '\0';
 
} /* hex2ascii () */
 
 
/*---------------------------------------------------------------------------*/
/*!Set the program counter
 
This sets the value in the NPC SPR. Not completely trivial, since this is
actually cached in cpu_state.pc. Any reset of the NPC also involves
clearing the delay state and setting the pcnext global.
 
Only actually do this if the requested address is different to the current
NPC (avoids clearing the delay pipe).
 
@param[in] addr The address to use */
/*---------------------------------------------------------------------------*/
static void
set_npc (uint32_t addr)
{
// First set the chain
gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
 
 
if (addr != get_npc())
{
 
gdb_write_reg(NPC_CPU_REG_ADD, addr);
if (STALLED == stallState)
{
if (DEBUG_GDB) printf("set_npc(): New NPC value (0x%08x) written and locally cached \n", addr);
npcCachedValue = addr;
npcIsCached = 1;
}
else
{
if (DEBUG_GDB) printf("set_npc(): New NPC value (0x%08x) written \n", addr);
npcIsCached = 0;
}
 
}
else
return;
 
} /* set_npc () */
 
 
//! Read the value of the Next Program Counter (a SPR)
 
//! 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),
//! so we must cache the NPC. As soon as the processor is unstalled, this
//! cached value becomes invalid.
 
//! If we are stalled and the value has been cached, use it. If we are stalled
//! and the value has not been cached, cache it (for efficiency) and use
//! it. Otherwise read the corresponding SPR.
 
//! @return The value of the NPC
static uint32_t get_npc ()
{
uint32_t current_npc;
 
if (STALLED == stallState)
{
if (npcIsCached == 0)
{
err = gdb_set_chain(SC_RISC_DEBUG);
err = gdb_read_reg(NPC_CPU_REG_ADD, &npcCachedValue);
if(err > 0){
printf("Error %d reading NPC\n", err);
rsp_client_close ();
return 0;
}
if (DEBUG_GDB) printf("get_npc(): caching newly read NPC value (0x%08x)\n",npcCachedValue);
 
 
npcIsCached = 1;
}
else
if (DEBUG_GDB) printf("get_npc(): reading cached NPC value (0x%08x)\n",npcCachedValue);
 
return npcCachedValue;
}
else
{
err = gdb_read_reg(NPC_CPU_REG_ADD, &current_npc);
if(err > 0){
printf("Error %d reading NPC\n", err);
rsp_client_close ();
return 0;
}
return current_npc;
 
}
} // get_npc ()
 
 
 
/*---------------------------------------------------------------------------*/
/*!Send a packet acknowledging an exception has occurred
 
This is only called if there is a client FD to talk to */
/*---------------------------------------------------------------------------*/
static void
rsp_report_exception (void)
{
struct rsp_buf buffer;
 
/* Construct a signal received packet */
buffer.data[0] = 'S';
buffer.data[1] = hexchars[rsp.sigval >> 4];
buffer.data[2] = hexchars[rsp.sigval % 16];
buffer.data[3] = 0;
buffer.len = strlen (buffer.data);
 
put_packet (&buffer);
 
} /* rsp_report_exception () */
 
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP continue request
 
Parse the command to see if there is an address. Uses the underlying
generic continue function, with EXCEPT_NONE.
 
@param[in] p_buf The full continue packet */
/*---------------------------------------------------------------------------*/
static void
rsp_continue (struct rsp_buf *p_buf)
{
uint32_t addr; /* Address to continue from, if any */
 
// First set the chain
err = gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
if(err > 0){
printf("Error %d to set RISC Debug Interface chain in the CONTINUE command 'c'\n", err);
rsp_client_close ();
return;
}
 
if (0 == strcmp ("c", p_buf->data))
{
// Arc Sim Code --> addr = cpu_state.pc; /* Default uses current NPC */
/* ---------- NPC ---------- */
addr = get_npc();
}
else if (1 != sscanf (p_buf->data, "c%x", &addr))
{
fprintf (stderr,
"Warning: RSP continue address %s not recognized: ignored\n",
p_buf->data);
 
// Arc Sim Code --> addr = cpu_state.pc; /* Default uses current NPC */
/* ---------- NPC ---------- */
addr = get_npc();
}
 
if (DEBUG_GDB) printf("rsp_continue() --> Read NPC = 0x%08x\n", addr);
 
rsp_continue_generic (addr, EXCEPT_NONE);
 
} /* rsp_continue () */
 
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP continue with signal request
 
Currently null. Will use the underlying generic continue function.
 
@param[in] p_buf The full continue with signal packet */
/*---------------------------------------------------------------------------*/
static void
rsp_continue_with_signal (struct rsp_buf *p_buf)
{
printf ("RSP continue with signal '%s' received\n", p_buf->data);
 
} /* rsp_continue_with_signal () */
 
 
/*---------------------------------------------------------------------------*/
/*!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) */
/*---------------------------------------------------------------------------*/
static void
rsp_continue_generic (uint32_t addr,
uint32_t except)
{
uint32_t temp_uint32;
/* Set the address as the value of the next program counter */
set_npc (addr);
/* Clear Debug Reason Register (DRR) 0x3015 */
// Arc sim --> cpu_state.sprs[SPR_DRR] = 0;
if(gdb_write_reg(DRR_CPU_REG_ADD, 0)) printf("Error write to DRR register\n");
/* Clear watchpoint break generation in Debug Mode Register 2 (DMR2) 0x3011 */
// Arc sim --> cpu_state.sprs[SPR_DMR2] &= ~SPR_DMR2_WGB;
if(gdb_read_reg(DMR2_CPU_REG_ADD, &temp_uint32)) printf("Error read from DMR2 register\n");
temp_uint32 &= ~SPR_DMR2_WGB;
if(gdb_write_reg(DMR2_CPU_REG_ADD, temp_uint32)) printf("Error write to DMR2 register\n");
/* Clear the single step trigger in Debug Mode Register 1 (DMR1) Register 0x3010 */
// Arc sim --> cpu_state.sprs[SPR_DMR1] &= ~SPR_DMR1_ST;
if(gdb_read_reg(DMR1_CPU_REG_ADD, &temp_uint32)) printf("Error read from DMR1 register\n");
temp_uint32 &= ~SPR_DMR1_ST;
if(gdb_write_reg(DMR1_CPU_REG_ADD, temp_uint32)) printf("Error write to DMR1 register\n");
/* Set traps to be handled by the debug unit in the Debug Stop Register (DSR) Register 0x3014 */
// Arc sim --> cpu_state.sprs[SPR_DSR] |= SPR_DSR_TE;
if(gdb_read_reg(DSR_CPU_REG_ADD, &temp_uint32)) printf("Error read from DSR register\n");
temp_uint32 |= SPR_DSR_TE;
if(gdb_write_reg(DSR_CPU_REG_ADD, temp_uint32)) printf("Error write to DSR register\n");
 
/* Unstall the processor */
set_stall_state (0);
 
/* Note the GDB client is now waiting for a reply. */
rsp.client_waiting = 1;
 
} /* rsp_continue_generic () */
 
 
/*---------------------------------------------------------------------------*/
/*!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. */
/*---------------------------------------------------------------------------*/
static void
rsp_read_all_regs (void)
{
struct rsp_buf buffer; /* Buffer for the reply */
int r; /* Register index */
uint32_t temp_uint32;
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
// First set the chain
gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
// Read all GPRs
for (r = 0; r < MAX_GPRS; r++){
err = gdb_read_reg(0x400 + r, &temp_uint32);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in gdb_read_reg at reg. %d\n", err, r);
put_str_packet ("E01");
return;
}
reg2hex (temp_uint32, &(buffer.data[r * 8]));
if (DEBUG_GDB_DUMP_DATA){
switch(r % 4)
{
case 0:
printf("gpr%02d 0x%08x ", r, temp_uint32);
break;
case 1:
case 2:
printf("0x%08x ", temp_uint32);
break;
case 3:
printf("0x%08x\n", temp_uint32);
break;
default:
break;
}
}
}
/* ---------- PPC ---------- */
err = gdb_read_reg(PPC_CPU_REG_ADD, &temp_uint32);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in gdb_read_reg read --> PPC\n", err);
put_str_packet ("E01");
return;
}
reg2hex (temp_uint32, &(buffer.data[PPC_REGNUM * 8]));
if (DEBUG_GDB_DUMP_DATA) printf("PPC 0x%08x\n", temp_uint32);
/* ---------- NPC ---------- */
temp_uint32 = get_npc();
/*
err = gdb_read_reg(NPC_CPU_REG_ADD, &temp_uint32);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in gdb_read_reg read --> NPC\n", err);
put_str_packet ("E01");
return;
}
*/
reg2hex (temp_uint32, &(buffer.data[NPC_REGNUM * 8]));
if (DEBUG_GDB_DUMP_DATA) printf("NPC 0x%08x\n", temp_uint32);
/* ---------- SR ---------- */
err = gdb_read_reg(SR_CPU_REG_ADD, &temp_uint32);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in gdb_read_reg read --> SP\n", err);
put_str_packet ("E01");
return;
}
reg2hex (temp_uint32, &(buffer.data[SR_REGNUM * 8]));
if (DEBUG_GDB_DUMP_DATA) printf("SR 0x%08x\n", temp_uint32);
 
/* Finalize the packet and send it */
buffer.data[NUM_REGS * 8] = 0;
buffer.len = NUM_REGS * 8;
 
put_packet (&buffer);
return;
} /* rsp_read_all_regs () */
 
 
/*---------------------------------------------------------------------------*/
/*!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".
 
@param[in] p_buf The original packet request. */
/*---------------------------------------------------------------------------*/
static void
rsp_write_all_regs (struct rsp_buf *p_buf)
{
uint32_t regnum; /* Register index */
// char valstr[9]; /* Allow for EOS on the string */
 
// /* Check for valid data */
// if (0 != (strcmp ("G", p_buf->data)) && (GDB_BUF_MAX != strlen(p_buf->data)))
// {
// fprintf (stderr, "Warning: Failed to recognize RSP write register "
// "command: %s\n", p_buf->data);
// // put_str_packet ("E01");
// return;
// }
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
// First set the chain
err = gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
if(err > 0){
if (DEBUG_GDB) printf("Error %d in gdb_set_chain\n", err);
put_str_packet ("E01");
return;
}
 
/* ---------- GPRS ---------- */
for (regnum = 0; regnum < MAX_GPRS; regnum++)
{
err = gdb_write_reg(0x400 + regnum, hex2reg (&p_buf->data[regnum * 8 + 1]));
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_write_reg write --> GPRS\n", err);
put_str_packet ("E01");
return;
}
}
/* ---------- PPC ---------- */
err = gdb_write_reg(PPC_CPU_REG_ADD, hex2reg (&p_buf->data[PPC_REGNUM * 8 + 1]));
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_write_reg write --> PPC\n", err);
put_str_packet ("E01");
return;
}
/* ---------- SR ---------- */
err = gdb_write_reg(SR_CPU_REG_ADD, hex2reg (&p_buf->data[SR_REGNUM * 8 + 1]));
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_write_reg write --> SR\n", err);
put_str_packet ("E01");
return;
}
/* ---------- NPC ---------- */
set_npc(hex2reg (&p_buf->data[NPC_REGNUM * 8 + 1]));
/*
err = gdb_write_reg(NPC_CPU_REG_ADD, hex2reg (&p_buf->data[NPC_REGNUM * 8 + 1]));
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_write_reg write --> NPC\n", err);
put_str_packet ("E01");
return;
}
*/
/* Acknowledge. TODO: We always succeed at present, even if the data was
defective. */
put_str_packet ("OK");
} /* rsp_write_all_regs () */
 
 
/*---------------------------------------------------------------------------*/
/* 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.
 
@note This function reuses p_buf, so trashes the original command.
 
@param[in] p_buf The command received */
/*---------------------------------------------------------------------------*/
static void rsp_read_mem (struct rsp_buf *p_buf)
{
unsigned int addr; /* Where to read the memory */
int len; /* Number of bytes to read */
int off; /* Offset into the memory */
uint32_t temp_uint32 = 0;
char *rec_buf;
 
 
if (2 != sscanf (p_buf->data, "m%x,%x:", &addr, &len))
{
fprintf (stderr, "Warning: Failed to recognize RSP read memory "
"command: %s\n", p_buf->data);
put_str_packet ("E01");
return;
}
 
/* Make sure we won't overflow the buffer (2 chars per byte) */
if ((len * 2) >= GDB_BUF_MAX)
{
fprintf (stderr, "Warning: Memory read %s too large for RSP packet: "
"truncated\n", p_buf->data);
len = (GDB_BUF_MAX - 1) / 2;
}
 
if(!(rec_buf = (char*)malloc(len))) {
put_str_packet ("E01");
ProtocolClean(0, JTAG_PROXY_OUT_OF_MEMORY);
return;
}
 
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
// Set chain 5 --> Wishbone Memory chain
err = gdb_set_chain(SC_WISHBONE);
if(err){
if (DEBUG_GDB) printf("Error %d in gdb_set_chain\n", err);
put_str_packet ("E01");
return;
}
 
// Read the data from Wishbone Memory chain
err = gdb_read_block(addr, (uint32_t*)rec_buf, len);
if(err){
put_str_packet ("E01");
return;
}
 
/* Refill the buffer with the reply */
for( off = 0 ; off < len ; off ++ ) {
;
temp_uint32 = (temp_uint32 << 8) | (0x000000ff & *(rec_buf + off));
if((off %4 ) == 3){
temp_uint32 = htonl(temp_uint32);
reg2hex (temp_uint32, &(p_buf->data[off * 2 - 6]));
}
if (DEBUG_GDB_BLOCK_DATA){
switch(off % 16)
{
case 3:
printf("Add 0x%08x Data 0x%08x ", addr + off - 3, temp_uint32);
break;
case 7:
case 11:
printf("0x%08x ", temp_uint32);
break;
case 15:
printf("0x%08x\n", temp_uint32);
break;
default:
break;
}
if ((len - off == 1) && (off % 16) < 15) printf("\n");
}
}
if (DEBUG_GDB && (err > 0)) printf("\nError %x\n", err);fflush (stdout);
free(rec_buf);
p_buf->data[off * 2] = 0; /* End of string */
p_buf->len = strlen (p_buf->data);
put_packet (p_buf);
} /* rsp_read_mem () */
 
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP write memory (symbolic) request ("M")
 
Syntax is:
 
M<addr>,<length>:<data>
 
Example: M4015cc,2:c320#
(Write the value 0xc320 to address 0x4015cc.)
 
An example target response:
+ $OK#
 
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.
 
@note This function reuses p_buf, so trashes the original command.
 
@param[in] p_buf The command received */
/*---------------------------------------------------------------------------*/
static void
rsp_write_mem (struct rsp_buf *p_buf)
{
unsigned int addr; /* Where to write the memory */
int len; /* Number of bytes to write */
char *symdat; /* Pointer to the symboli data */
int datlen; /* Number of digits in symbolic data */
int off; /* Offset into the memory */
int nibc; /* Nibbel counter */
uint32_t val;
if (2 != sscanf (p_buf->data, "M%x,%x:", &addr, &len))
{
fprintf (stderr, "Warning: Failed to recognize RSP write memory "
"command: %s\n", p_buf->data);
put_str_packet ("E01");
return;
}
 
/* Find the start of the data and check there is the amount we expect. */
symdat = (char*) memchr ((const void *)p_buf->data, ':', GDB_BUF_MAX) + 1;
datlen = p_buf->len - (symdat - p_buf->data);
 
/* Sanity check */
if (len * 2 != datlen)
{
fprintf (stderr, "Warning: Write of %d digits requested, but %d digits "
"supplied: packet ignored\n", len * 2, datlen );
put_str_packet ("E01");
return;
}
 
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
 
// Set chain 5 --> Wishbone Memory chain
err = gdb_set_chain(SC_WISHBONE);
if(err){
put_str_packet ("E01");
return;
}
val = 0;
off = 0;
/* Write the bytes to memory */
for (nibc = 0; nibc < datlen; nibc++)
{
val |= 0x0000000f & hex (symdat[nibc]);
if(nibc % 8 == 7){
err = gdb_write_block(addr + off, &val, 4);
if (DEBUG_GDB) printf("Error %x\n", err);fflush (stdout);
if(err){
put_str_packet ("E01");
return;
}
val = 0;
off += 4;
}
val <<= 4;
}
put_str_packet ("OK");
} /* rsp_write_mem () */
 
 
/*---------------------------------------------------------------------------*/
/*!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.
 
@param[in] p_buf The original packet request. Reused for the reply. */
/*---------------------------------------------------------------------------*/
static void
rsp_read_reg (struct rsp_buf *p_buf)
{
unsigned int regnum;
uint32_t temp_uint32;
 
/* Break out the fields from the data */
if (1 != sscanf (p_buf->data, "p%x", &regnum))
{
fprintf (stderr, "Warning: Failed to recognize RSP read register "
"command: %s\n", p_buf->data);
put_str_packet ("E01");
return;
}
 
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
// First set the chain
err = gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
if(err > 0){
if (DEBUG_GDB) printf("Error %d in gdb_set_chain\n", err);
put_str_packet ("E01");
return;
}
 
/* Get the relevant register */
if (regnum < MAX_GPRS)
{
err = gdb_read_reg(0x400 + regnum, &temp_uint32);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_read_reg at reg. %d \n", err, regnum);
put_str_packet ("E01");
return;
}
reg2hex (temp_uint32, p_buf->data);
}
else if (PPC_REGNUM == regnum) /* ---------- PPC ---------- */
{
err = gdb_read_reg(PPC_CPU_REG_ADD, &temp_uint32);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_read_reg read --> PPC\n", err);
put_str_packet ("E01");
return;
}
reg2hex (temp_uint32, p_buf->data);
}
else if (NPC_REGNUM == regnum) /* ---------- NPC ---------- */
{
temp_uint32 = get_npc();
/*
err = gdb_read_reg(NPC_CPU_REG_ADD, &temp_uint32);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_read_reg read --> PPC\n", err);
put_str_packet ("E01");
return;
}
*/
reg2hex (temp_uint32, p_buf->data);
}
else if (SR_REGNUM == regnum) /* ---------- SR ---------- */
{
err = gdb_read_reg(SR_CPU_REG_ADD, &temp_uint32);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_read_reg read --> PPC\n", err);
put_str_packet ("E01");
return;
}
reg2hex (temp_uint32, p_buf->data);
}
else
{
/* Error response if we don't know the register */
fprintf (stderr, "Warning: Attempt to read unknown register 0x%x: "
"ignored\n", regnum);
put_str_packet ("E01");
return;
}
 
p_buf->len = strlen (p_buf->data);
put_packet (p_buf);
 
} /* rsp_read_reg () */
 
/*---------------------------------------------------------------------------*/
/*!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.
 
@param[in] p_buf The original packet request. */
/*---------------------------------------------------------------------------*/
static void
rsp_write_reg (struct rsp_buf *p_buf)
{
unsigned int regnum;
char valstr[9]; /* Allow for EOS on the string */
// int err = 0;
 
/* Break out the fields from the data */
if (2 != sscanf (p_buf->data, "P%x=%8s", &regnum, valstr))
{
fprintf (stderr, "Warning: Failed to recognize RSP write register "
"command: %s\n", p_buf->data);
put_str_packet ("E01");
return;
}
 
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
// First set the chain
err = gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
if(err > 0){
if (DEBUG_GDB) printf("Error %d in gdb_set_chain\n", err);
put_str_packet ("E01");
return;
}
 
/* Set the relevant register */
if (regnum < MAX_GPRS) /* ---------- GPRS ---------- */
{
err = gdb_write_reg(0x400 + regnum, hex2reg (valstr));
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_write_reg write --> GPRS\n", err);
put_str_packet ("E01");
return;
}
}
else if (PPC_REGNUM == regnum) /* ---------- PPC ---------- */
{
err = gdb_write_reg(PPC_CPU_REG_ADD, hex2reg (valstr));
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_write_reg write --> PPC\n", err);
put_str_packet ("E01");
return;
}
}
else if (NPC_REGNUM == regnum) /* ---------- NPC ---------- */
{
set_npc(hex2reg (valstr));
/*
err = gdb_write_reg(NPC_CPU_REG_ADD, hex2reg (valstr));
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_write_reg write --> NPC\n", err);
put_str_packet ("E01");
return;
}
*/
}
else if (SR_REGNUM == regnum) /* ---------- SR ---------- */
{
err = gdb_write_reg(SR_CPU_REG_ADD, hex2reg (valstr));
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_write_reg write --> SR\n", err);
put_str_packet ("E01");
return;
}
}
else
{
/* Error response if we don't know the register */
fprintf (stderr, "Warning: Attempt to write unknown register 0x%x: "
"ignored\n", regnum);
put_str_packet ("E01");
return;
}
 
put_str_packet ("OK");
 
} /* rsp_write_reg () */
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP query request
 
@param[in] p_buf The request */
/*---------------------------------------------------------------------------*/
static void
rsp_query (struct rsp_buf *p_buf)
{
if (0 == strcmp ("qC", p_buf->data))
{
/* Return the current thread ID (unsigned hex). A null response
indicates to use the previously selected thread. Since we do not
support a thread concept, this is the appropriate response. */
put_str_packet ("");
}
else if (0 == strncmp ("qCRC", p_buf->data, strlen ("qCRC")))
{
/* Return CRC of memory area */
fprintf (stderr, "Warning: RSP CRC query not supported\n");
put_str_packet ("E01");
}
else if (0 == strcmp ("qfThreadInfo", p_buf->data))
{
/* Return info about active threads. We return just '-1' */
put_str_packet ("m-1");
}
else if (0 == strcmp ("qsThreadInfo", p_buf->data))
{
/* Return info about more active threads. We have no more, so return the
end of list marker, 'l' */
put_str_packet ("l");
}
else if (0 == strncmp ("qGetTLSAddr:", p_buf->data, strlen ("qGetTLSAddr:")))
{
/* We don't support this feature */
put_str_packet ("");
}
else if (0 == strncmp ("qL", p_buf->data, strlen ("qL")))
{
/* Deprecated and replaced by 'qfThreadInfo' */
fprintf (stderr, "Warning: RSP qL deprecated: no info returned\n");
put_str_packet ("qM001");
}
else if (0 == strcmp ("qOffsets", p_buf->data))
{
/* Report any relocation */
put_str_packet ("Text=0;Data=0;Bss=0");
}
else if (0 == strncmp ("qP", p_buf->data, strlen ("qP")))
{
/* Deprecated and replaced by 'qThreadExtraInfo' */
fprintf (stderr, "Warning: RSP qP deprecated: no info returned\n");
put_str_packet ("");
}
else if (0 == strncmp ("qRcmd,", p_buf->data, strlen ("qRcmd,")))
{
/* This is used to interface to commands to do "stuff" */
rsp_command (p_buf);
}
else if (0 == strncmp ("qSupported", p_buf->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. */
setup_or32(); // setup cpu
char reply[GDB_BUF_MAX];
sprintf (reply, "PacketSize=%x", GDB_BUF_MAX);
put_str_packet (reply);
}
else if (0 == strncmp ("qSymbol:", p_buf->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! */
put_str_packet ("OK");
}
else if (0 == strncmp ("qThreadExtraInfo,", p_buf->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 (p_buf->data, "%02x%02x%02x%02x%02x%02x%02x%02x%02x",
'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0);
p_buf->len = strlen (p_buf->data);
put_packet (p_buf);
}
else if (0 == strncmp ("qXfer:", p_buf->data, strlen ("qXfer:")))
{
/* For now we support no 'qXfer' requests, but these should not be
expected, since they were not reported by 'qSupported' */
fprintf (stderr, "Warning: RSP 'qXfer' not supported: ignored\n");
put_str_packet ("");
}
else
{
fprintf (stderr, "Unrecognized RSP query: ignored\n");
}
} /* rsp_query () */
 
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP qRcmd request
 
The actual command follows the "qRcmd," in ASCII encoded to hex
 
@param[in] p_buf The request in full */
/*---------------------------------------------------------------------------*/
static void
rsp_command (struct rsp_buf *p_buf)
{
char cmd[GDB_BUF_MAX];
unsigned int regno;
uint32_t temp_uint32;
 
hex2ascii (cmd, &(p_buf->data[strlen ("qRcmd,")]));
 
/* Work out which command it is */
if (0 == strncmp ("readspr ", cmd, strlen ("readspr")))
{
/* Parse and return error if we fail */
if( 1 != sscanf (cmd, "readspr %4x", &regno))
{
fprintf (stderr, "Warning: qRcmd %s not recognized: ignored\n", cmd);
put_str_packet ("E01");
return;
}
/* SPR out of range */
if (regno > MAX_SPRS)
{
fprintf (stderr, "Warning: qRcmd readspr %x too large: ignored\n",
regno);
put_str_packet ("E01");
return;
}
/* Construct the reply */
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
// First set the chain
gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
// special case for NPC
if(regno == NPC_CPU_REG_ADD)
temp_uint32 = get_npc();
else
{
err = gdb_read_reg(regno, &temp_uint32);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_command at reg. %x \n", err, regno);
}
else{
reg2hex (temp_uint32, cmd);
if (DEBUG_GDB) printf("Error %d Command readspr Read reg. %x = 0x%08x\n", err, regno, temp_uint32);
}
}
// pack the result into the buffer to send back
sprintf (cmd, "%8x", (unsigned int)temp_uint32);
ascii2hex (p_buf->data, cmd);
p_buf->len = strlen (p_buf->data);
put_packet (p_buf);
}
else if (0 == strncmp ("writespr ", cmd, strlen ("writespr")))
{
unsigned int regno;
uint32_t val;
/* Parse and return error if we fail */
if( 2 != sscanf (cmd, "writespr %4x %8x", &regno, &val))
{
fprintf (stderr, "Warning: qRcmd %s not recognized: ignored\n",
cmd);
put_str_packet ("E01");
return;
}
/* SPR out of range */
if (regno > MAX_SPRS)
{
fprintf (stderr, "Warning: qRcmd writespr %x too large: ignored\n",
regno);
put_str_packet ("E01");
return;
}
 
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
// First set the chain
gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
/* set the relevant register */
// special case for NPC
if(regno == NPC_CPU_REG_ADD)
set_npc(val);
else
{
err = gdb_write_reg(regno, val);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_command write Reg. %x = 0x%08x\n", err, regno, val);
put_str_packet ("E01");
return;
}
else{
if (DEBUG_GDB) printf("Error %d Command writespr Write reg. %x = 0x%08x\n", err, regno, val);
}
}
put_str_packet ("OK");
}
} /* rsp_command () */
 
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP set request
 
@param[in] p_buf The request */
/*---------------------------------------------------------------------------*/
static void
rsp_set (struct rsp_buf *p_buf)
{
if (0 == strncmp ("QPassSignals:", p_buf->data, strlen ("QPassSignals:")))
{
/* Passing signals not supported */
put_str_packet ("");
}
else if ((0 == strncmp ("QTDP", p_buf->data, strlen ("QTDP"))) ||
(0 == strncmp ("QFrame", p_buf->data, strlen ("QFrame"))) ||
(0 == strcmp ("QTStart", p_buf->data)) ||
(0 == strcmp ("QTStop", p_buf->data)) ||
(0 == strcmp ("QTinit", p_buf->data)) ||
(0 == strncmp ("QTro", p_buf->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. */
put_str_packet ("");
}
else
{
fprintf (stderr, "Unrecognized RSP set request: ignored\n");
}
} /* rsp_set () */
 
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP restart request
 
For now we just put the program counter back to the one used with the last
vRun request. There is no point in unstalling the processor, since we'll
never get control back. */
/*---------------------------------------------------------------------------*/
static void
rsp_restart (void)
{
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
// First set the chain
err = gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
if(err > 0){
if (DEBUG_GDB) printf("Error %d in gdb_set_chain\n", err);
put_str_packet ("E01");
return;
}
// OR32 Arc sim equivalent --> set_npc (rsp.start_addr);
/* Set NPC to reset vector 0x100 */
set_npc(rsp.start_addr);
/*
err = gdb_write_reg(NPC_CPU_REG_ADD, rsp.start_addr);
if(err > 0){
if (DEBUG_GDB) printf("Error %d in rsp_restart write Reg. %x = 0x%08x\n", err, NPC_CPU_REG_ADD, rsp.start_addr);
put_str_packet ("E01");
return;
}
else{
if (DEBUG_GDB) printf("Error %d Command Reset. Set NPC to Start vector %x = 0x%08x\n", err, NPC_CPU_REG_ADD, rsp.start_addr);
}
*/
} /* rsp_restart () */
 
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP step request
 
Parse the command to see if there is an address. Uses the underlying
generic step function, with EXCEPT_NONE.
 
@param[in] p_buf The full step packet */
/*---------------------------------------------------------------------------*/
static void
rsp_step (struct rsp_buf *p_buf)
{
uint32_t addr; /* The address to step from, if any */
 
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
// First set the chain
err = gdb_set_chain(SC_RISC_DEBUG); /* 1 RISC Debug Interface chain */
if(err > 0){
printf("Error %d to set RISC Debug Interface chain in the STEP command 's'\n", err);
rsp_client_close ();
return;
}
 
if (0 == strcmp ("s", p_buf->data))
{
// Arc Sim Code --> addr = cpu_state.pc; /* Default uses current NPC */
/* ---------- Npc ---------- */
addr = get_npc();
/*
err = gdb_read_reg(NPC_CPU_REG_ADD, &addr);
if(err > 0){
printf("Error %d to read NPC in the STEP command 's'\n", err);
rsp_client_close ();
return;
}
*/
}
else if (1 != sscanf (p_buf->data, "s%x", &addr))
{
fprintf (stderr,
"Warning: RSP step address %s not recognized: ignored\n",
p_buf->data);
 
// Arc Sim Code --> addr = cpu_state.pc; /* Default uses current NPC */
/* ---------- NPC ---------- */
addr = get_npc();
/*
err = gdb_read_reg(NPC_CPU_REG_ADD, &addr);
if(err > 0){
printf("Error %d to read NPC in the STEP command 's'\n", err);
rsp_client_close ();
return;
}
*/
}
 
//if (DEBUG_GDB) printf("rsp_step() --> Read NPC = 0x%08x\n", addr);
rsp_step_generic (addr, EXCEPT_NONE);
 
} /* rsp_step () */
 
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP step with signal request
 
Currently null. Will use the underlying generic step function.
 
@param[in] p_buf The full step with signal packet */
/*---------------------------------------------------------------------------*/
static void
rsp_step_with_signal (struct rsp_buf *p_buf)
{
printf ("RSP step with signal '%s' received\n", p_buf->data);
 
} /* rsp_step_with_signal () */
 
 
/*---------------------------------------------------------------------------*/
/*!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.
 
@param[in] addr Address from which to step
@param[in] except The exception to use (if any) */
/*---------------------------------------------------------------------------*/
static void
rsp_step_generic (uint32_t addr,
uint32_t except)
{
uint32_t temp_uint32;
/* Set the address as the value of the next program counter */
set_npc (addr);
/* Clear Debug Reason Register (DRR) 0x3015 */
// Arc sim --> cpu_state.sprs[SPR_DRR] = 0;
if(gdb_write_reg(DRR_CPU_REG_ADD, 0)) printf("Error write to DRR register\n");
/* Clear watchpoint break generation in Debug Mode Register 2 (DMR2) 0x3011 */
// Arc sim --> cpu_state.sprs[SPR_DMR2] &= ~SPR_DMR2_WGB;
if(gdb_read_reg(DMR2_CPU_REG_ADD, &temp_uint32)) printf("Error read from DMR2 register\n");
temp_uint32 &= ~SPR_DMR2_WGB;
if(gdb_write_reg(DMR2_CPU_REG_ADD, temp_uint32)) printf("Error write to DMR2 register\n");
/* Set the single step trigger in Debug Mode Register 1 (DMR1) Register 0x3010 */
// Arc sim --> cpu_state.sprs[SPR_DMR1] |= SPR_DMR1_ST;
if(gdb_read_reg(DMR1_CPU_REG_ADD, &temp_uint32)) printf("Error read from DMR1 register\n");
temp_uint32 |= SPR_DMR1_ST;
if(gdb_write_reg(DMR1_CPU_REG_ADD, temp_uint32)) printf("Error write to DMR1 register\n");
/* Set traps to be handled by the debug unit in the Debug Stop Register (DSR) Register 0x3014 */
// Arc sim --> cpu_state.sprs[SPR_DSR] |= SPR_DSR_TE;
if(gdb_read_reg(DSR_CPU_REG_ADD, &temp_uint32)) printf("Error read from DSR register\n");
temp_uint32 |= SPR_DSR_TE;
if(gdb_write_reg(DSR_CPU_REG_ADD, temp_uint32)) printf("Error write to DSR register\n");
 
/* Unstall the processor */
set_stall_state (0);
 
/* Note the GDB client is now waiting for a reply. */
rsp.client_waiting = 1;
 
} /* rsp_step_generic () */
 
 
/*---------------------------------------------------------------------------*/
/*!Handle a RSP 'v' packet
 
These are commands associated with executing the code on the target
 
@param[in] p_buf The request */
/*---------------------------------------------------------------------------*/
static void
rsp_vpkt (struct rsp_buf *p_buf)
{
if (0 == strncmp ("vAttach;", p_buf->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. */
put_str_packet ("S05");
return;
}
else if (0 == strcmp ("vCont?", p_buf->data))
{
/* For now we don't support this. */
put_str_packet ("");
return;
}
else if (0 == strncmp ("vCont", p_buf->data, strlen ("vCont")))
{
/* This shouldn't happen, because we've reported non-support via vCont?
above */
fprintf (stderr, "Warning: RSP vCont not supported: ignored\n" );
return;
}
else if (0 == strncmp ("vFile:", p_buf->data, strlen ("vFile:")))
{
/* For now we don't support this. */
fprintf (stderr, "Warning: RSP vFile not supported: ignored\n" );
put_str_packet ("");
return;
}
else if (0 == strncmp ("vFlashErase:", p_buf->data, strlen ("vFlashErase:")))
{
/* For now we don't support this. */
fprintf (stderr, "Warning: RSP vFlashErase not supported: ignored\n" );
put_str_packet ("E01");
return;
}
else if (0 == strncmp ("vFlashWrite:", p_buf->data, strlen ("vFlashWrite:")))
{
/* For now we don't support this. */
fprintf (stderr, "Warning: RSP vFlashWrite not supported: ignored\n" );
put_str_packet ("E01");
return;
}
else if (0 == strcmp ("vFlashDone", p_buf->data))
{
/* For now we don't support this. */
fprintf (stderr, "Warning: RSP vFlashDone not supported: ignored\n" );
put_str_packet ("E01");
return;
}
else if (0 == strncmp ("vRun;", p_buf->data, strlen ("vRun;")))
{
/* We shouldn't be given any args, but check for this */
if (p_buf->len > (int) strlen ("vRun;"))
{
fprintf (stderr, "Warning: Unexpected arguments to RSP vRun "
"command: ignored\n");
}
 
/* Restart the current program. However unlike a "R" packet, "vRun"
should behave as though it has just stopped. We use signal
5 (TRAP). */
rsp_restart ();
put_str_packet ("S05");
}
else
{
fprintf (stderr, "Warning: Unknown RSP 'v' packet type %s: ignored\n",
p_buf->data);
put_str_packet ("E01");
return;
}
} /* rsp_vpkt () */
 
 
/*---------------------------------------------------------------------------*/
/*!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. However the number
of data bytes may be greater, since '#', '$' and '}' are escaped by
preceding them by '}' and oring with 0x20.
 
@param[in] p_buf The command received */
/*---------------------------------------------------------------------------*/
static void
rsp_write_mem_bin (struct rsp_buf *p_buf)
{
unsigned int addr; /* Where to write the memory */
int len; /* Number of bytes to write */
char *bindat; /* Pointer to the binary data */
int off = 0; /* Offset to start of binary data */
int newlen; /* Number of bytes in bin data */
 
if (2 != sscanf (p_buf->data, "X%x,%x:", &addr, &len))
{
fprintf (stderr, "Warning: Failed to recognize RSP write memory "
"command: %s\n", p_buf->data);
put_str_packet ("E01");
return;
}
 
/* Find the start of the data and "unescape" it */
bindat = p_buf->data;
while(off < GDB_BUF_MAX){
if(bindat[off] == ':'){
bindat = bindat + off + 1;
off++;
break;
}
off++;
}
if(off >= GDB_BUF_MAX){
put_str_packet ("E01");
return;
}
newlen = rsp_unescape (bindat, p_buf->len - off);
 
/* Sanity check */
if (newlen != len)
{
int minlen = len < newlen ? len : newlen;
 
fprintf (stderr, "Warning: Write of %d bytes requested, but %d bytes "
"supplied. %d will be written\n", len, newlen, minlen);
len = minlen;
}
 
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
// Set chain 5 --> Wishbone Memory chain
err = gdb_set_chain(SC_WISHBONE);
if(err){
put_str_packet ("E01");
return;
}
/* Write the bytes to memory */
if (len)
{
swap_buf(bindat, len);
if (DEBUG_GDB_BLOCK_DATA){
uint32_t temp_uint32;
for (off = 0; off < len; off++){
temp_uint32 = (temp_uint32 << 8) | (0x000000ff & bindat[off]);
if((off %4 ) == 3){
temp_uint32 = htonl(temp_uint32);
}
switch(off % 16)
{
case 3:
printf("Add 0x%08x Data 0x%08x ", addr + off - 3, temp_uint32);
break;
case 7:
case 11:
printf("0x%08x ", temp_uint32);
break;
case 15:
printf("0x%08x\n", temp_uint32);
break;
default:
break;
}
if ((len - off == 1) && (off % 16) < 15) printf("\n");
}
}
err = gdb_write_block(addr, (uint32_t*)bindat, len);
if(err){
put_str_packet ("E01");
return;
}
if (DEBUG_GDB) printf("Error %x\n", err);fflush (stdout);
}
put_str_packet ("OK");
} /* rsp_write_mem_bin () */
 
/*---------------------------------------------------------------------------*/
/*!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
 
@param[in] p_buf The command received */
/*---------------------------------------------------------------------------*/
static void
rsp_remove_matchpoint (struct rsp_buf *p_buf)
{
enum mp_type type; /* What sort of matchpoint */
uint32_t addr; /* Address specified */
int len; /* Matchpoint length (not used) */
struct mp_entry *mpe; /* Info about the replaced instr */
 
/* Break out the instruction */
if (3 != sscanf (p_buf->data, "z%1d,%x,%1d", (int *)&type, &addr, &len))
{
fprintf (stderr, "Warning: RSP matchpoint deletion request not "
"recognized: ignored\n");
put_str_packet ("E01");
return;
}
 
/* Sanity check that the length is 4 */
if (4 != len)
{
fprintf (stderr, "Warning: RSP matchpoint deletion length %d not "
"valid: 4 assumed\n", len);
len = 4;
}
 
/* Sort out the type of matchpoint */
switch (type)
{
case BP_MEMORY:
/* Memory breakpoint - replace the original instruction. */
mpe = mp_hash_delete (type, addr);
 
/* If the BP hasn't yet been deleted, put the original instruction
back. Don't forget to free the hash table entry afterwards. */
if (NULL != mpe)
{
// Arc Sim Code --> set_program32 (addr, mpe->instr);
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
 
// Set chain 5 --> Wishbone Memory chain
err = gdb_set_chain(SC_WISHBONE);
if(err){
put_str_packet ("E01");
return;
}
err = gdb_write_block(addr, &mpe->instr, 4);
if(err){
put_str_packet ("E01");
return;
}
free (mpe);
}
 
put_str_packet ("OK");
return;
case BP_HARDWARE:
put_str_packet (""); /* Not supported */
return;
 
case WP_WRITE:
put_str_packet (""); /* Not supported */
return;
 
case WP_READ:
put_str_packet (""); /* Not supported */
return;
 
case WP_ACCESS:
put_str_packet (""); /* Not supported */
return;
 
default:
fprintf (stderr, "Warning: RSP matchpoint type %d not "
"recognized: ignored\n", type);
put_str_packet ("E01");
return;
 
}
} /* rsp_remove_matchpoint () */
 
/*---------------------------------------------------------------------------*/
/*!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
 
@param[in] p_buf The command received */
/*---------------------------------------------------------------------------*/
static void
rsp_insert_matchpoint (struct rsp_buf *p_buf)
{
enum mp_type type; /* What sort of matchpoint */
uint32_t addr; /* Address specified */
int len; /* Matchpoint length (not used) */
uint32_t instr;
 
/* Break out the instruction */
if (3 != sscanf (p_buf->data, "Z%1d,%x,%1d", (int *)&type, &addr, &len))
{
fprintf (stderr, "Warning: RSP matchpoint insertion request not "
"recognized: ignored\n");
put_str_packet ("E01");
return;
}
 
/* Sanity check that the length is 4 */
if (4 != len)
{
fprintf (stderr, "Warning: RSP matchpoint insertion length %d not "
"valid: 4 assumed\n", len);
len = 4;
}
 
/* Sort out the type of matchpoint */
switch (type)
{
case BP_MEMORY: // software-breakpoint Z0 break
/* Memory breakpoint - substitute a TRAP instruction */
// Make sure the processor is stalled
gdb_ensure_or1k_stalled();
// Set chain 5 --> Wishbone Memory chain
gdb_set_chain(SC_WISHBONE);
// Read the data from Wishbone Memory chain
// Arc Sim Code --> mp_hash_add (type, addr, eval_direct32 (addr, 0, 0));
gdb_read_block(addr, &instr, 4);
 
mp_hash_add (type, addr, instr);
// Arc Sim Code --> set_program32 (addr, OR1K_TRAP_INSTR);
instr = OR1K_TRAP_INSTR;
err = gdb_write_block(addr, &instr, 4);
if(err){
put_str_packet ("E01");
return;
}
put_str_packet ("OK");
return;
case BP_HARDWARE: // hardware-breakpoint Z1 hbreak
put_str_packet (""); /* Not supported */
return;
case WP_WRITE: // write-watchpoint Z2 watch
put_str_packet (""); /* Not supported */
return;
case WP_READ: // read-watchpoint Z3 rwatch
put_str_packet (""); /* Not supported */
return;
 
case WP_ACCESS: // access-watchpoint Z4 awatch
put_str_packet (""); /* Not supported */
return;
 
default:
fprintf (stderr, "Warning: RSP matchpoint type %d not "
"recognized: ignored\n", type);
put_str_packet ("E01");
return;
}
} /* rsp_insert_matchpoint () */
 
 
/*---------------------------------------------------------------------------
Setup the or32 to init state
 
---------------------------------------------------------------------------*/
void setup_or32(void)
{
uint32_t temp_uint32;
// First set the chain
err = gdb_set_chain(SC_REGISTER); /* 4 Register Chain */
if(err > 0){
if (DEBUG_GDB) printf("Error %d in gdb_set_chain\n", err);
}
if(gdb_read_reg(0x04, &temp_uint32)) printf("Error read from register\n");
if (DEBUG_GDB) printf("Read from chain 4 SC_REGISTER at add 0x00000004 = 0x%08x\n", temp_uint32 );
if(gdb_write_reg(0x04, 0x00000001)) printf("Error write to register\n");
if (DEBUG_GDB) printf("Write to chain 4 SC_REGISTER at add 0x00000004 = 0x00000001\n");
// if(gdb_read_reg(0x04, &temp_uint32)) printf("Error read from register\n");
// if (DEBUG_GDB) printf("Read from chain 4 SC_REGISTER at add 0x00000004 = 0x%08x\n", temp_uint32 );
// if(gdb_read_reg(0x04, &temp_uint32)) printf("Error read from register\n");
// if (DEBUG_GDB) printf("Read from chain 4 SC_REGISTER at add 0x00000004 = 0x%08x\n", temp_uint32 );
if(gdb_write_reg(0x00, 0x01000001)) printf("Error write to register\n");
if (DEBUG_GDB) printf("Write to chain 4 SC_REGISTER at add 0x00000000 = 0x01000001\n");
}
 
// Function to check if the processor is stalled - if not then stall it.
// this is useful in the event that GDB thinks the processor is stalled, but has, in fact
// been hard reset on the board and is running.
static void gdb_ensure_or1k_stalled()
{
// Disable continual checking that the or1k is stalled
#ifdef ENABLE_OR1K_STALL_CHECK
unsigned char stalled;
dbg_cpu0_read_ctrl(0, &stalled);
if ((stalled & 0x1) != 0x1)
{
if (DEBUG_GDB)
printf("Processor not stalled, like we thought\n");
// Set the TAP controller to its OR1k chain
dbg_set_tap_ir(JI_DEBUG);
gdb_chain = -1;
 
// Processor isn't stalled, contrary to what we though, so stall it
printf("Stalling or1k\n");
dbg_cpu0_write_ctrl(0, 0x01); // stall or1k
}
#endif
return;
}
 
 
int gdb_read_reg(uint32_t adr, uint32_t *data) {
switch (gdb_chain) {
case SC_RISC_DEBUG: return dbg_cpu0_read(adr, data) ? ERR_CRC : ERR_NONE;
case SC_REGISTER: return dbg_cpu0_read_ctrl(adr, (unsigned char*)data) ?
ERR_CRC : ERR_NONE;
case SC_WISHBONE: return dbg_wb_read32(adr, data) ? ERR_CRC : ERR_NONE;
case SC_TRACE: *data = 0; return 0;
default: return JTAG_PROXY_INVALID_CHAIN;
}
}
 
int gdb_write_reg(uint32_t adr, uint32_t data) {
switch (gdb_chain) { /* remap registers, to be compatible with jp1 */
case SC_RISC_DEBUG: if (adr == JTAG_RISCOP) adr = 0x00;
return dbg_cpu0_write(adr, data) ? ERR_CRC : ERR_NONE;
case SC_REGISTER: return dbg_cpu0_write_ctrl(adr, data) ? ERR_CRC : ERR_NONE;
case SC_WISHBONE: return dbg_wb_write32(adr, data) ? ERR_CRC : ERR_NONE;
case SC_TRACE: return 0;
default: return JTAG_PROXY_INVALID_CHAIN;
}
}
 
int gdb_read_block(uint32_t adr, uint32_t *data, int len) {
if (DEBUG_CMDS) printf("rb %d\n", gdb_chain);
switch (gdb_chain) {
case SC_WISHBONE: return dbg_wb_read_block32(adr, data, len) ?
ERR_CRC : ERR_NONE;
default: return JTAG_PROXY_INVALID_CHAIN;
}
}
 
int gdb_write_block(uint32_t adr, uint32_t *data, int len) {
if (DEBUG_CMDS) printf("wb %d\n", gdb_chain);
switch (gdb_chain) {
case SC_WISHBONE: return dbg_wb_write_block32(adr, data, len) ?
ERR_CRC : ERR_NONE;
default: return JTAG_PROXY_INVALID_CHAIN;
}
}
 
int gdb_set_chain(int chain) {
int rv;
switch (chain) {
case SC_RISC_DEBUG:
case SC_REGISTER:
case SC_TRACE:
case SC_WISHBONE: gdb_chain = chain;
rv = ERR_NONE;
break;
default: rv = JTAG_PROXY_INVALID_CHAIN;
break;
}
return rv;
}
 
/* Added by CZ 24/05/01 */
int GetServerSocket(const char* name, const char* proto, int port) {
struct servent *service;
struct protoent *protocol;
struct sockaddr_in sa;
struct hostent *hp;
int sockfd;
char myname[256];
//int flags; --changed to socklen_t for c++?! -- Julius
socklen_t flags;
char sTemp[256];
 
/* First, get the protocol number of TCP */
if (!(protocol = getprotobyname(proto))) {
sprintf(sTemp, "Unable to load protocol \"%s\"", proto);
perror(sTemp);
return 0;
}
tcp_level = protocol->p_proto; /* Save for later */
 
/* If we weren't passed a non standard port, get the port
from the services directory. */
if (!port && (service = getservbyname(name, protocol->p_name)))
port = ntohs(service->s_port);
/* Create the socket using the TCP protocol */
if ((sockfd = socket(PF_INET, SOCK_STREAM, protocol->p_proto)) < 0) {
perror("Unable to create socket");
return 0;
}
flags = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const char*)&flags, sizeof(int)) < 0) {
sprintf(sTemp, "Can not set SO_REUSEADDR option on socket %d", sockfd);
perror(sTemp);
close(sockfd);
return 0;
}
 
/* The server should also be non blocking. Get the current flags. */
if(fcntl(sockfd, F_GETFL, &flags) < 0) {
sprintf(sTemp, "Unable to get flags for socket %d", sockfd);
perror(sTemp);
close(sockfd);
return 0;
}
 
/* Set the nonblocking flag */
if(fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
sprintf(sTemp, "Unable to set flags for socket %d to value 0x%08x",
sockfd, flags | O_NONBLOCK);
perror(sTemp);
close(sockfd);
return 0;
}
 
/* Find out what our address is */
memset(&sa, 0, sizeof(struct sockaddr_in));
gethostname(myname, sizeof(myname));
if(!(hp = gethostbyname(myname))) {
perror("Unable to read hostname");
close(sockfd);
return 0;
}
/* Bind our socket to the appropriate address */
sa.sin_family = hp->h_addrtype;
sa.sin_port = htons(port);
if(bind(sockfd, (struct sockaddr*)&sa, sizeof(struct sockaddr_in)) < 0) {
sprintf(sTemp, "Unable to bind socket %d to port %d", sockfd, port);
perror(sTemp);
close(sockfd);
return 0;
}
serverIP = sa.sin_addr.s_addr;
flags = sizeof(struct sockaddr_in);
if(getsockname(sockfd, (struct sockaddr*)&sa, &flags) < 0) {
sprintf(sTemp, "Unable to get socket information for socket %d", sockfd);
perror(sTemp);
close(sockfd);
return 0;
}
serverPort = ntohs(sa.sin_port);
 
/* Set the backlog to 1 connections */
if(listen(sockfd, 1) < 0) {
sprintf(sTemp, "Unable to set backlog on socket %d to %d", sockfd, 1);
perror(sTemp);
close(sockfd);
return 0;
}
 
return sockfd;
}
 
//void HandleServerSocket(Boolean block) {
void HandleServerSocket(void) {
struct pollfd fds[2];
int n;
uint32_t temp_uint32;
 
rebuild:
n = 0;
if(!server_fd && !gdb_fd) return;
if(server_fd) {
fds[n].fd = server_fd;
fds[n].events = POLLIN;
fds[n++].revents = 0;
}
if(gdb_fd) {
fds[n].fd = gdb_fd;
fds[n].events = POLLIN;
fds[n++].revents = 0;
}
while(1) {
switch(poll(fds, n, -1)) {
case 0:
case -1:
if(errno == EINTR) continue;
perror("poll");
server_fd = 0;
return;
default:
/* Make sure to handle the gdb port first! */
if (gdb_fd && ((fds[0].revents && !server_fd) || (fds[1].revents && server_fd)))
{
int revents = server_fd ? fds[1].revents : fds[0].revents;
if (revents & POLLIN){
/* If we have an unacknowledged exception tell the GDB client. If this
exception was a trap due to a memory breakpoint, then adjust the NPC. */
if (rsp.client_waiting)
{
err = gdb_read_reg(PPC_CPU_REG_ADD, &temp_uint32);
if(err) printf("Error read from PPC register\n");
if ((TARGET_SIGNAL_TRAP == rsp.sigval) &&
(NULL != mp_hash_lookup (BP_MEMORY, temp_uint32)))
{
set_npc (temp_uint32);
}
rsp_report_exception();
rsp.client_waiting = 0; /* No longer waiting */
}
GDBRequest();
}
else {/* Error Occurred */
printf("\n%sSocket closed.\n",printTime());
//fprintf(stderr,
//"Received flags 0x%08x on gdb socket. Shutting down.\n", revents);
close(gdb_fd);
gdb_fd = 0;
}
}
// Go to blocking accept() instead of looping around through poll(),
// takes a loot of CPU resources and it doesn't work when
 
if(!gdb_fd)
{
JTAGRequest();
rsp.client_waiting = 0; /* No longer waiting */
goto rebuild;
}
if(fds[0].revents && server_fd) {
if(fds[0].revents & POLLIN) {
JTAGRequest();
rsp.client_waiting = 0; /* No longer waiting */
goto rebuild;
} else { /* Error Occurred */
fprintf(stderr,
"Received flags 0x%08x on server. Shutting down.\n",
fds[0].revents);
close(server_fd);
server_fd = 0;
serverPort = 0;
serverIP = 0;
return;
}
}
break;
} /* End of switch statement */
} /* End of while statement */
}
 
void JTAGRequest(void) {
struct sockaddr_in sa;
struct sockaddr* addr = (struct sockaddr*)&sa;
//int n = sizeof(struct sockaddr_in); --changed to socklen_t from int type
socklen_t n = sizeof(struct sockaddr_in);
int fd = accept(server_fd, addr, &n);
int on_off = 0; /* Turn off Nagel's algorithm on the socket */
int flags;
char sTemp[256];
if (DEBUG_GDB) printf("JTAGRequest\n");
 
if(fd < 0) {
/* This is valid, because a connection could have started,
and then terminated due to a protocol error or user
initiation before the accept could take place. */
if(errno != EWOULDBLOCK && errno != EAGAIN) {
perror("accept");
close(server_fd);
server_fd = 0;
serverPort = 0;
serverIP = 0;
}
return;
}
 
if(gdb_fd) {
close(fd);
return;
}
 
if(fcntl(fd, F_GETFL, &flags) < 0) {
sprintf(sTemp, "Unable to get flags for gdb socket %d", fd);
perror(sTemp);
close(fd);
return;
}
/* Rene
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
sprintf(sTemp, "Unable to set flags for gdb socket %d to value 0x%08x",
fd, flags | O_NONBLOCK);
perror(sTemp);
close(fd);
return;
} Rene */
 
if(setsockopt(fd, tcp_level, TCP_NODELAY, &on_off, sizeof(int)) < 0) {
sprintf(sTemp, "Unable to disable Nagel's algorithm for socket %d.\nsetsockopt", fd);
perror(sTemp);
close(fd);
return;
}
 
printf("\n%sConnection established from %s on port %d\n", printTime(),inet_ntoa(sa.sin_addr),ntohs(sa.sin_port));
gdb_fd = fd;
}
 
 
/*---------------------------------------------------------------------------
* Decode the GDB command.
*
*---------------------------------------------------------------------------*/
static void GDBRequest(void) {
JTAGProxyWriteMessage msg_write;
JTAGProxyReadMessage msg_read;
JTAGProxyChainMessage msg_chain;
JTAGProxyWriteResponse resp_write;
JTAGProxyReadResponse resp_read;
JTAGProxyChainResponse resp_chain;
JTAGProxyBlockWriteMessage *msg_bwrite;
JTAGProxyBlockReadMessage msg_bread;
JTAGProxyBlockWriteResponse resp_bwrite;
JTAGProxyBlockReadResponse *resp_bread;
char *p_buf;
uint32_t command;
uint32_t length;
int len, i;
 
/* First, we must read the incomming command */
if(gdb_read(&command, sizeof(uint32_t)) < 0) {
client_close ('1');
return;
}
command = ntohl(command);
 
if(gdb_read(&length, sizeof(uint32_t)) < 0) {
client_close ('2');
return;
}
length = ntohl(length);
if (DEBUG_GDB) printf("\n%s-----------------------------------------------------\nCommand %d Length %d ", printTime(), command, length);
 
if (DEBUG_GDB){
switch(command){
case JTAG_COMMAND_READ:
printf("JTAG_COMMAND_READ \n");
break;
case JTAG_COMMAND_WRITE:
printf("JTAG_COMMAND_WRITE \n");
break;
case JTAG_COMMAND_BLOCK_READ:
printf("JTAG_COMMAND_BLOCK_READ \n");
break;
case JTAG_COMMAND_BLOCK_WRITE:
printf("JTAG_COMMAND_BLOCK_WRITE\n");
break;
case JTAG_COMMAND_CHAIN:
printf("JTAG_COMMAND_CHAIN \n");
break;
}
}
/* Now, verify the protocol and implement the command */
switch(command) {
case JTAG_COMMAND_WRITE:
if(length != sizeof(msg_write) - 8) {
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
return;
}
p_buf = (char*)&msg_write;
if(gdb_read(&p_buf[8], length) < 0) {
client_close ('3');
return;
}
msg_write.address = ntohl(msg_write.address);
msg_write.data_H = ntohl(msg_write.data_H);
msg_write.data_L = ntohl(msg_write.data_L);
err = gdb_write_reg(msg_write.address, msg_write.data_L);
resp_write.status = htonl(err);
if (DEBUG_GDB) printf("Write Reg to Chain %d at add 0x%08x -> H-Data 0x%08x L-Data 0x%08x Error %d",
gdb_chain, msg_write.address, msg_write.data_H, msg_write.data_L, err);fflush (stdout);
if(gdb_write(&resp_write, sizeof(resp_write)) < 0) {
client_close ('4');
return;
}
break;
case JTAG_COMMAND_READ:
if(length != sizeof(msg_read) - 8) {
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
return;
}
p_buf = (char*)&msg_read;
if(gdb_read(&p_buf[8], length) < 0) {
client_close ('5');
return;
}
msg_read.address = ntohl(msg_read.address);
err = gdb_read_reg(msg_read.address, (uint32_t *)&resp_read.data_L);
if (DEBUG_GDB) printf("Read Reg from Chain %d at add 0x%08x", gdb_chain, msg_read.address);
resp_read.status = htonl(err);
resp_read.data_H = 0;
resp_read.data_L = htonl(resp_read.data_L);
if(gdb_write(&resp_read, sizeof(resp_read)) < 0) {
client_close ('6');
return;
}
if (DEBUG_GDB) printf(" --> Data 0x%08x Error %d\n", htonl(resp_read.data_L), err);fflush (stdout);
break;
case JTAG_COMMAND_BLOCK_WRITE:
if(length < sizeof(JTAGProxyBlockWriteMessage)-8) {
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
return;
}
if(!(p_buf = (char*)malloc(8+length))) {
ProtocolClean(length, JTAG_PROXY_OUT_OF_MEMORY);
return;
}
msg_bwrite = (JTAGProxyBlockWriteMessage*)p_buf;
if(gdb_read(&p_buf[8], length) < 0) {
client_close ('5');
free(p_buf);
return;
}
msg_bwrite->address = ntohl(msg_bwrite->address);
msg_bwrite->nRegisters = ntohl(msg_bwrite->nRegisters);
if (DEBUG_GDB) printf("Block Write to Chain %d start add 0x%08x Write %d (32 bit words):\n\n", gdb_chain, msg_bwrite->address, msg_bwrite->nRegisters);
for(i=0;i<msg_bwrite->nRegisters;i++) {
msg_bwrite->data[i] = ntohl(msg_bwrite->data[i]);
if (DEBUG_GDB_BLOCK_DATA){
if ((i % 4) == 0) printf("Add 0x%08x Data 0x%08x ", msg_bwrite->address + (i * 4), msg_bwrite->data[i]);
else if ((i % 4) == 3) printf("0x%08x\n", msg_bwrite->data[i]);
else printf("0x%08x ", msg_bwrite->data[i]);
 
// add a new line on the last data, but not if it is the last one in the colum
if ((msg_bwrite->nRegisters - i == 1) && (i % 4) < 3) printf("\n");
}
}
err = gdb_write_block(msg_bwrite->address, (uint32_t*)msg_bwrite->data, msg_bwrite->nRegisters * 4);
if (DEBUG_GDB) printf("Error %x\n", err);fflush (stdout);
resp_bwrite.status = htonl(err);
free(p_buf);
msg_bwrite = (JTAGProxyBlockWriteMessage *)NULL;
p_buf = (char *)msg_bwrite;
if(gdb_write(&resp_bwrite, sizeof(resp_bwrite)) < 0) {
client_close ('4');
return;
}
break;
case JTAG_COMMAND_BLOCK_READ:
if(length != sizeof(msg_bread) - 8) {
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
return;
}
p_buf = (char*)&msg_bread;
if(gdb_read(&p_buf[8], length) < 0) {
client_close ('5');
return;
}
msg_bread.address = ntohl(msg_bread.address);
msg_bread.nRegisters = ntohl(msg_bread.nRegisters);
if (DEBUG_GDB) printf("Block Read from Chain %d start add 0x%08x Read %d (32 bit words):\n\n", gdb_chain, msg_bread.address, msg_bread.nRegisters);
len = sizeof(JTAGProxyBlockReadResponse) + 4*(msg_bread.nRegisters-1);
if(!(p_buf = (char*)malloc(len))) {
ProtocolClean(0, JTAG_PROXY_OUT_OF_MEMORY);
return;
}
resp_bread = (JTAGProxyBlockReadResponse*)p_buf;
err = gdb_read_block(msg_bread.address, (uint32_t*)resp_bread->data, msg_bread.nRegisters * 4);
for(i=0;i<msg_bread.nRegisters;i++) {
/* Read previous, address next one. */
resp_bread->data[i] = htonl(resp_bread->data[i]);
if (DEBUG_GDB_BLOCK_DATA){
if ((i % 4) == 0) printf("Add 0x%08x Data 0x%08x ", msg_bread.address + (i * 4), htonl(resp_bread->data[i]));
else if ((i % 4) == 3) printf("0x%08x\n", htonl(resp_bread->data[i]));
else printf("0x%08x ", htonl(resp_bread->data[i]));
}
// add a new line on the last data, but not if it is the last one in the colum
if ((msg_bread.nRegisters - i == 1) && (i % 4) < 3) printf("\n");
}
resp_bread->status = htonl(err);
resp_bread->nRegisters = htonl(msg_bread.nRegisters);
if (DEBUG_GDB) printf("\nError %x\n", err);fflush (stdout);
if(gdb_write(resp_bread, len) < 0) {
client_close ('6');
free(p_buf);
return;
}
free(p_buf);
resp_bread = (JTAGProxyBlockReadResponse *)NULL;
p_buf = (char *)resp_bread;
break;
case JTAG_COMMAND_CHAIN:
if(length != sizeof(msg_chain) - 8) {
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
return;
}
p_buf = (char*)&msg_chain;
if(gdb_read(&p_buf[8], sizeof(msg_chain)-8) < 0) {
client_close ('7');
return;
}
msg_chain.chain = htonl(msg_chain.chain);
err = gdb_set_chain(msg_chain.chain);
resp_chain.status = htonl(err);
if (DEBUG_GDB){
switch(msg_chain.chain){
case SC_GLOBAL: /* 0 Global BS Chain */
printf("Set Chain %d Global BS Chain Error %x\n", msg_chain.chain, err);
break;
case SC_RISC_DEBUG: /* 1 RISC Debug Interface chain */
printf("Set Chain %d RISC Debug Interface chain Error %x\n", msg_chain.chain, err);
break;
case SC_RISC_TEST: /* 2 RISC Test Chain */
printf("Set Chain %d RISC Test Chain Error %x\n", msg_chain.chain, err);
break;
case SC_TRACE: /* 3 Trace Chain */
printf("Set Chain %d Trace Chain Error %x\n", msg_chain.chain, err);
break;
case SC_REGISTER: /* 4 Register Chain */
printf("Set Chain %d Register Chain Error %x\n", msg_chain.chain, err);
break;
case SC_WISHBONE: /* 5 Memory chain */
printf("Set Chain %d Wishbone Memory chain Error %x\n", msg_chain.chain, err);
break;
case SC_BLOCK: /* 6 Block Chains */
printf("Set Chain %d Block Chains Error %x\n", msg_chain.chain, err);
break;
default: /* Invalid chain */
printf("Set Chain %d Invalid chain Error %x\n", msg_chain.chain, err);
break;
}
fflush (stdout);
}
if(gdb_write(&resp_chain, sizeof(resp_chain)) < 0) {
client_close ('8');
return;
}
break;
default:
perror("Unknown JTAG command.");fflush (stdout);
ProtocolClean(length, JTAG_PROXY_COMMAND_NOT_IMPLEMENTED);
break;
}
}
 
static void ProtocolClean(int length, int32_t err) {
char buffer[4096];
 
err = htonl(err);
if(((gdb_read(buffer, length) < 0) || (gdb_write(&err, sizeof(err)) < 0)) && gdb_fd) {
perror("gdb socket - 9");
close(gdb_fd);
gdb_fd = 0;
}
}
 
static int gdb_write(void* p_buf, int len) {
int n;
char* w_buf = (char*)p_buf;
struct pollfd block;
 
while(len) {
if((n = write(gdb_fd, w_buf, len)) < 0) {
switch(errno) {
case EWOULDBLOCK: /* or EAGAIN */
/* We've been called on a descriptor marked
for nonblocking I/O. We better simulate
blocking behavior. */
block.fd = gdb_fd;
block.events = POLLOUT;
block.revents = 0;
poll(&block, 1, -1);
continue;
case EINTR:
continue;
case EPIPE:
close(gdb_fd);
gdb_fd = 0;
return -1;
default:
return -1;
}
} else {
len -= n;
w_buf += n;
}
}
return 0;
}
 
static int gdb_read(void* p_buf, int len) {
int n;
char* r_buf = (char*)p_buf;
struct pollfd block;
 
while(len) {
if((n = read(gdb_fd, r_buf, len)) < 0) {
switch(errno) {
case EWOULDBLOCK: /* or EAGAIN */
/* We've been called on a descriptor marked
for nonblocking I/O. We better simulate
blocking behavior. */
block.fd = gdb_fd;
block.events = POLLIN;
block.revents = 0;
poll(&block, 1, -1);
continue;
case EINTR:
continue;
default:
return -1;
}
} else if(n == 0) {
close(gdb_fd);
gdb_fd = 0;
return -1;
} else {
len -= n;
r_buf += n;
}
}
return 0;
}
 
 
/*****************************************************************************
* Close the connection to the client if it is open
******************************************************************************/
static void client_close (char err)
{
if(gdb_fd) {
perror("gdb socket - " + err);
close(gdb_fd);
gdb_fd = 0;
}
} /* client_close () */
 
 
/*---------------------------------------------------------------------------*/
/* Swap a buffer of 4-byte from 1234 to 4321
 
parameter[in] p_buf and len
parameter[out] none */
/*---------------------------------------------------------------------------*/
static void swap_buf(char* p_buf, int len)
{
int temp;
int n = 0;
 
if (len > 2)
{
while(n < len){
// swap 0 and 3
temp = p_buf[n];
p_buf[n] = p_buf[n + 3];
p_buf[n + 3] = temp;
// swap 1 and 2
temp = p_buf[n + 1];
p_buf[n + 1] = p_buf[n + 2];
p_buf[n + 2] = temp;
n += 4;
}
}
}
 
 
/*---------------------------------------------------------------------------*/
/*!Set the stall state of the processor
 
@param[in] state If non-zero stall the processor. */
/*---------------------------------------------------------------------------*/
static void
set_stall_state (int state)
{
if(state == 0)
{
err = dbg_cpu0_write_ctrl(0, 0); /* unstall or1k */
stallState = UNSTALLED;
npcIsCached = 0;
rsp.sigval = TARGET_SIGNAL_NONE;
}
else
{
err = dbg_cpu0_write_ctrl(0, 0x01); /* stall or1k */
stallState = STALLED;
}
 
if(err > 0 && DEBUG_GDB)printf("Error %d in set_stall_state Stall state = %d\n", err, state);
 
} /* set_stall_state () */
 
 
/*---------------------------------------------------------------------------*/
/*!Set the reset bit of the processor's control reg in debug interface
*/
/*---------------------------------------------------------------------------*/
static void
reset_or1k (void)
{
err = dbg_cpu0_write_ctrl(0, 0x02); /* reset or1k */
if(err > 0 && DEBUG_GDB)printf("Error %d in reset_or1k()\n", err);
 
} /* reset_or1k () */
 
/*---------------------------------------------------------------------------*/
/*!Close down the connection with GDB in the event of a kill signal
 
*/
/*---------------------------------------------------------------------------*/
void gdb_close()
{
rsp_client_close();
client_close('0');
// Maybe do other things here!
}
/vpi/verilog/vpi_debug_defines.v
0,0 → 1,216
//////////////////////////////////////////////////////////////////////
//// ////
//// ORPSoC Testbench ////
//// ////
//// Description ////
//// ORPSoC VPI Debugging Testbench defines file ////
//// ////
//// To Do: ////
//// ////
//// ////
//// Author(s): ////
//// - jb, jb@orsoc.se ////
//// ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2009 Authors and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file 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 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source 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 source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`timescale 1ns/10ps
// Defines from the following files:
// tap_defines.v
 
// Define IDCODE Value
`define IDCODE_VALUE 32'h14951185
 
// Length of the Instruction register
`define IR_LENGTH 4
 
// Supported Instructions
`define EXTEST 4'b0000
`define SAMPLE_PRELOAD 4'b0001
`define IDCODE 4'b0010
`define DEBUG 4'b1000
`define MBIST 4'b1001
`define BYPASS 4'b1111
 
// Number of cells in boundary scan chain
`define BS_CELL_NB 32'd558
 
//dbg_defines.v
 
// Length of the MODULE ID register
`define DBG_TOP_MODULE_ID_LENGTH 4
 
// Length of data
`define DBG_TOP_MODULE_DATA_LEN `DBG_TOP_MODULE_ID_LENGTH + 1
`define DBG_TOP_DATA_CNT 3
 
// Length of status
`define DBG_TOP_STATUS_LEN 3'd4
`define DBG_TOP_STATUS_CNT_WIDTH 3
 
// Length of the CRC
`define DBG_TOP_CRC_LEN 32
`define DBG_TOP_CRC_CNT 6
 
// Chains
`define DBG_TOP_WISHBONE_DEBUG_MODULE 4'h0
`define DBG_TOP_CPU0_DEBUG_MODULE 4'h1
`define DBG_TOP_CPU1_DEBUG_MODULE 4'h2
 
// dbg_wb_defines.v
 
// If WISHBONE sub-module is supported uncomment the folowing line
`define DBG_WISHBONE_SUPPORTED
 
// If CPU_0 sub-module is supported uncomment the folowing line
`define DBG_CPU0_SUPPORTED
 
// If CPU_1 sub-module is supported uncomment the folowing line
//`define DBG_CPU1_SUPPORTED
 
// If more debug info is needed, uncomment the follofing line
//`define DBG_MORE_INFO
 
 
// Defining length of the command
`define DBG_WB_CMD_LEN 3'd4
`define DBG_WB_CMD_CNT_WIDTH 3
 
// Defining length of the access_type field
`define DBG_WB_ACC_TYPE_LEN 3'd4
 
// Defining length of the address
`define DBG_WB_ADR_LEN 6'd32
 
// Defining length of the length register
`define DBG_WB_LEN_LEN 5'd16
 
// Defining total length of the DR needed
`define DBG_WB_DR_LEN (`DBG_WB_ACC_TYPE_LEN + `DBG_WB_ADR_LEN + `DBG_WB_LEN_LEN)
 
// Defining length of the CRC
`define DBG_WB_CRC_LEN 6'd32
`define DBG_WB_CRC_CNT_WIDTH 6
 
// Defining length of status
`define DBG_WB_STATUS_LEN 3'd4
`define DBG_WB_STATUS_CNT_WIDTH 3
 
// Defining length of the data
`define DBG_WB_DATA_CNT_WIDTH (`DBG_WB_LEN_LEN + 3)
`define DBG_WB_DATA_CNT_LIM_WIDTH `DBG_WB_LEN_LEN
 
//Defining commands
`define DBG_WB_GO 4'h0
`define DBG_WB_RD_COMM 4'h1
`define DBG_WB_WR_COMM 4'h2
 
// Defining access types for wishbone
`define DBG_WB_WRITE8 4'h0
`define DBG_WB_WRITE16 4'h1
`define DBG_WB_WRITE32 4'h2
`define DBG_WB_READ8 4'h4
`define DBG_WB_READ16 4'h5
`define DBG_WB_READ32 4'h6
 
// dbg_cpu_defines.v
 
 
// Defining length of the command
`define DBG_CPU_CMD_LEN 3'd4
`define DBG_CPU_CMD_CNT_WIDTH 3
 
// Defining length of the access_type field
`define DBG_CPU_ACC_TYPE_LEN 3'd4
 
// Defining length of the address
`define DBG_CPU_ADR_LEN 6'd32
 
// Defining length of the length register
`define DBG_CPU_LEN_LEN 5'd16
 
// Defining total length of the DR needed
//define DBG_CPU_DR_LEN (`DBG_CPU_ACC_TYPE_LEN + `DBG_CPU_ADR_LEN + `DBG_CPU_LEN_LEN)
`define DBG_CPU_DR_LEN 52
// Defining length of the CRC
`define DBG_CPU_CRC_LEN 6'd32
`define DBG_CPU_CRC_CNT_WIDTH 6
 
// Defining length of status
`define DBG_CPU_STATUS_LEN 3'd4
`define DBG_CPU_STATUS_CNT_WIDTH 3
 
// Defining length of the data
//define DBG_CPU_DATA_CNT_WIDTH `DBG_CPU_LEN_LEN + 3
`define DBG_CPU_DATA_CNT_WIDTH 19
//define DBG_CPU_DATA_CNT_LIM_WIDTH `DBG_CPU_LEN_LEN
`define DBG_CPU_DATA_CNT_LIM_WIDTH 16
// Defining length of the control register
`define DBG_CPU_CTRL_LEN 2
 
//Defining commands
`define DBG_CPU_GO 4'h0
`define DBG_CPU_RD_COMM 4'h1
`define DBG_CPU_WR_COMM 4'h2
`define DBG_CPU_RD_CTRL 4'h3
`define DBG_CPU_WR_CTRL 4'h4
 
// Defining access types for wishbone
`define DBG_CPU_WRITE 4'h2
`define DBG_CPU_READ 4'h6
 
 
// commands from jp_vpi
`define CMD_JTAG_SET_IR 4'h1
`define CMD_SET_DEBUG_CHAIN 4'h2
`define CMD_CPU_CTRL_WR 4'h3
`define CMD_CPU_CTRL_RD 4'h4
`define CMD_CPU_WR_REG 4'h5
`define CMD_CPU_RD_REG 4'h6
`define CMD_WB_WR32 4'h7
`define CMD_WB_RD32 4'h8
`define CMD_WB_BLOCK_WR32 4'h9
`define CMD_WB_BLOCK_RD32 4'ha
`define CMD_RESET 4'hb
`define CMD_READ_JTAG_ID 4'hc
`define CMD_GDB_DETACH 4'hd
 
// commands:
// 4'h1 jtag set instruction register (input: instruction value)
// 4'h2 set debug chain (dbg_set_command here) (input: chain value)
// 4'h3 cpu_ctrl_wr (input: ctrl value (2 bits))
// 4'h4 cpu_ctrl_rd (output: ctrl value (2bits))
// 4'h5 cpu wr reg (inputs: address, data)
// 4'h6 cpu rd reg (input: address; output: data)
// 4'h7 wb wr 32 (inputs: address, data)
// 4'h8 wb rd 32 (input: address; output: data)
// 4'h9 wb wr block 32 (inputs: address, length, data)
// 4'ha wb rd block 32 (inputs: address, length; output: data)
// 4'hb reset
// 4'hc read jtag id (output: data)
 
`define SDRAM_BASE_ADDRESS 32'h00000000
/vpi/verilog/vpi_debug_module.v
0,0 → 1,1613
//////////////////////////////////////////////////////////////////////
//// ////
//// ORPSoC Testbench ////
//// ////
//// Description ////
//// ORPSoC VPI Debugging Testbench file ////
//// ////
//// To Do: ////
//// ////
//// ////
//// Author(s): ////
//// - jb, jb@orsoc.se ////
//// ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2009 Authors and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file 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 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source 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 source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`timescale 1ns/10ps
 
`include "vpi_debug_defines.v"
 
// uncomment the following line to get more debug output for this module
//`define DEBUG_INFO
//`define VPI_DEBUG_INFO
 
module vpi_debug_module(tms, tck, tdi, tdo);
output tms;
output tck;
output tdi;
input tdo;
 
reg tms;
reg tck;
reg tdi;
reg [31:0] in_data_le, in_data_be;
reg err;
integer i;
reg [31:0] id;
reg [31:0] npc;
reg [31:0] ppc;
reg [31:0] r1;
reg [31:0] insn;
reg [31:0] result;
reg [31:0] tmp;
reg [31:0] crc_out;
reg [31:0] crc_in;
wire crc_match_in;
reg [`DBG_TOP_STATUS_LEN -1:0] status;
reg [`DBG_WB_STATUS_LEN -1:0] status_wb;
reg [`DBG_CPU_STATUS_LEN -1:0] status_cpu;
// Text used for easier debugging
reg [199:0] test_text;
reg [`DBG_WB_CMD_LEN -1:0] last_wb_cmd;
reg [`DBG_CPU_CMD_LEN -1:0] last_cpu_cmd;
reg [199:0] last_wb_cmd_text;
reg [199:0] last_cpu_cmd_text;
reg [31:0] data_storage [0:4095]; // Data storage (for write and read operations).
reg [18:0] length_global;
parameter Tp = 1;
//parameter Tck = 25; // Clock half period (Clok period = 50 ns => 20 MHz)
parameter Tck = 50; // Clock half period (Clok period = 100 ns => 10 MHz)
 
integer cmd;
integer block_cmd_length;
integer jtag_instn_val;
integer set_chain_val;
reg [1:0] cpu_ctrl_val; // two important bits for the ctrl reg
reg [31:0] cmd_adr;
reg [31:0] cmd_data;
 
initial
begin
$display("JTAG debug module with VPI interface enabled\n");
tck <=#Tp 1'b0;
tdi <=#Tp 1'bz;
tms <=#Tp 1'b0;
 
// Insert a #delay here because we need to
// wait until the PC isn't pointing to flash anymore
// (this is around 20k ns if the flash_crash boot code
// is being booted from, else much bigger, around 10mil ns)
#200_000 main;
end
task main;
begin
id <=#Tp 32'h00;
npc <=#Tp 32'h00;
ppc <=#Tp 32'h00;
insn <=#Tp 32'h00;
result <=#Tp 32'h00;
err <=#Tp 1'b0;
tmp <=#Tp 32'h00;
// execute some cycles
#50000;
reset_tap;
goto_run_test_idle;
 
//$init_rsp_server();
 
while (1) begin
// Check for incoming command
// wait until a command is sent
// poll with a delay here
cmd = -1;
while (cmd == -1)
begin
#1000 $check_for_command(cmd);
end
 
// now switch on the command
case (cmd)
`CMD_RESET : // reset
begin
// call reset task
reset_tap;
// and put TAP into run_test_idle state
goto_run_test_idle;
end
`CMD_JTAG_SET_IR : // set jtag instruction register
begin
$get_command_data(jtag_instn_val);
set_instruction(jtag_instn_val);
end
`CMD_SET_DEBUG_CHAIN : // set debug chain
begin
$get_command_data(set_chain_val);
module_select(set_chain_val, 1'b0); // {chain, gen_crc_err}
 
end
`CMD_CPU_CTRL_WR : // cpu CTRL write
begin
 
$get_command_data(cpu_ctrl_val);
 
debug_cpu_wr_ctrl(cpu_ctrl_val, "");
 
end
 
`CMD_CPU_CTRL_RD : // cpu CTRL read
begin
debug_cpu_rd_ctrl(cpu_ctrl_val);
 
$return_command_data(cpu_ctrl_val);
end
 
`CMD_CPU_WR_REG :
begin
$get_command_address(cmd_adr);
$get_command_data(cmd_data);
 
`ifdef VPI_DEBUG_INFO
$display("CPU reg write. adr: 0x%x (reg group: %d reg#: %d), val: 0x%x",
cmd_adr,cmd_adr[15:11], cmd_adr[10:0], cmd_data);
`endif
cpu_write_32(cmd_data, cmd_adr,16'h3);
end
`CMD_CPU_RD_REG :
begin
 
$get_command_address(cmd_adr);
 
cpu_read_32(cmd_data, cmd_adr, 16'h3);
 
`ifdef VPI_DEBUG_INFO
$display("CPU reg read. adr: 0x%x (reg group: %d reg#: %d), val: 0x%x",
cmd_adr,cmd_adr[15:11], cmd_adr[10:0], cmd_data);
`endif
 
$return_command_data(cmd_data);
end
`CMD_WB_WR32 :
begin
$get_command_address(cmd_adr);
 
$get_command_data(cmd_data);
 
wb_write_32(cmd_data, cmd_adr, 16'h3);
 
end
`CMD_WB_RD32 :
begin
 
$get_command_address(cmd_adr);
 
wb_read_32(cmd_data, cmd_adr, 16'h3);
 
$return_command_data(cmd_data);
end
`CMD_WB_BLOCK_WR32 :
begin
 
$get_command_address(cmd_adr);
$get_command_data(block_cmd_length);
 
$get_command_block_data(block_cmd_length, data_storage);
 
wb_block_write_32(cmd_adr ,block_cmd_length);
end
`CMD_WB_BLOCK_RD32 :
begin
$get_command_address(cmd_adr);
$get_command_data(block_cmd_length);
 
wb_block_read_32(cmd_adr, block_cmd_length);
$return_command_block_data(block_cmd_length, data_storage);
end
`CMD_READ_JTAG_ID :
begin
read_id_code(id);
$return_command_data(id);
end
`CMD_GDB_DETACH :
begin
 
$display("Debugging client disconnected. Finishing simulation");
$finish();
end
default:
begin
$display("Somehow got to the default case in the command case statement.");
$display("Command was: %x", cmd);
$display("Exiting...");
 
$finish();//shouldn't be here
end
endcase // case (cmd)
// send back response, which is currently nothing
// but could be used to signal something
$return_response();
end // while (1)
end
endtask // main
 
 
// Receiving data and calculating input crc
always @(posedge tck)
begin
in_data_be[31:1] <= #1 in_data_be[30:0];
in_data_be[0] <= #1 tdo;
in_data_le[31] <= #1 tdo;
in_data_le[30:0] <= #1 in_data_le[31:1];
end
 
// Generation of the TCK signal
task gen_clk;
input [31:0] number;
integer i;
begin
for(i=0; i<number; i=i+1)
begin
#Tck tck<=1;
#Tck tck<=0;
end
end
endtask
 
// TAP reset
task reset_tap;
begin
`ifdef DEBUG_INFO
$display("(%0t) Task reset_tap", $time);
`endif
tms<=#1 1'b1;
gen_clk(5);
end
endtask
 
 
// Goes to RunTestIdle state
task goto_run_test_idle;
begin
`ifdef DEBUG_INFO
$display("(%0t) Task goto_run_test_idle", $time);
`endif
tms<=#1 1'b0;
gen_clk(1);
end
endtask
 
// sets the instruction to the IR register and goes to the RunTestIdle state
task set_instruction;
input [3:0] instr;
integer i;
begin
`ifdef DEBUG_INFO
case (instr)
`EXTEST : $display("(%0t) Task set_instruction (EXTEST)", $time);
`SAMPLE_PRELOAD : $display("(%0t) Task set_instruction (SAMPLE_PRELOAD)", $time);
`IDCODE : $display("(%0t) Task set_instruction (IDCODE)", $time);
`DEBUG : $display("(%0t) Task set_instruction (DEBUG)", $time);
`MBIST : $display("(%0t) Task set_instruction (MBIST)", $time);
`BYPASS : $display("(%0t) Task set_instruction (BYPASS)", $time);
default
begin
$display("(%0t) Task set_instruction (Unsupported instruction !!!)", $time);
$display("\tERROR: Unsupported instruction !!!", $time);
$stop;
end
endcase
`endif
 
tms<=#1 1;
gen_clk(2);
tms<=#1 0;
gen_clk(2); // we are in shiftIR
 
for(i=0; i<`IR_LENGTH-1; i=i+1)
begin
tdi<=#1 instr[i];
gen_clk(1);
end
tdi<=#1 instr[i]; // last shift
tms<=#1 1; // going out of shiftIR
gen_clk(1);
tdi<=#1 'hz; // tri-state
gen_clk(1);
tms<=#1 0;
gen_clk(1); // we are in RunTestIdle
end
endtask
 
 
// send 32 bits through the device
task test_bypass;
input [31:0] in;
output [31:0] out;
integer i;
reg [31:0] out;
 
begin
tms<=#Tp 1;
gen_clk(1);
tms<=#Tp 0;
gen_clk(2); // we are in shiftDR
 
for(i=31; i>=0; i=i-1)
begin
tdi<=#Tp in[i];
gen_clk(1);
end
 
tms<=#Tp 1; // going out of shiftDR
gen_clk(1);
 
out <=#Tp in_data_be;
tdi<=#Tp 'hz;
 
gen_clk(1);
tms<=#Tp 0;
gen_clk(1); // we are in RunTestIdle
end
endtask
 
// Reads the ID code
task read_id_code;
output [31:0] code;
reg [31:0] code;
begin
`ifdef DEBUG_INFO
$display("(%0t) Task read_id_code", $time);
`endif
 
tms<=#1 1;
gen_clk(1);
tms<=#1 0;
gen_clk(2); // we are in shiftDR
tdi<=#1 0;
gen_clk(31);
tms<=#1 1; // going out of shiftIR
gen_clk(1);
code = in_data_le;
tdi<=#1 'hz; // tri-state
gen_clk(1);
tms<=#1 0;
gen_clk(1); // we are in RunTestIdle
end
endtask
 
// test bundary scan chain
task test_bs;
input [31:0] in;
output [31:0] out;
integer i;
reg [31:0] out;
 
begin
tms<=#Tp 1;
gen_clk(1);
tms<=#Tp 0;
gen_clk(2); // we are in shiftDR
 
for(i=31; i>=0; i=i-1)
begin
tdi<=#Tp in[i];
gen_clk(1);
end
 
gen_clk(`BS_CELL_NB-1);
tms<=#Tp 1; // going out of shiftDR
gen_clk(1);
 
out <=#Tp in_data_be;
 
gen_clk(1);
tms<=#Tp 0;
gen_clk(1); // we are in RunTestIdle
end
endtask
 
 
 
// sets the selected scan chain and goes to the RunTestIdle state
task module_select;
input [`DBG_TOP_MODULE_ID_LENGTH -1:0] data;
input gen_crc_err;
integer i;
begin
`ifdef DEBUG_INFO
case (data)
`DBG_TOP_CPU1_DEBUG_MODULE : $display("(%0t) Task module_select (DBG_TOP_CPU1_DEBUG_MODULE, gen_crc_err=%0d)", $time, gen_crc_err);
`DBG_TOP_CPU0_DEBUG_MODULE : $display("(%0t) Task module_select (DBG_TOP_CPU0_DEBUG_MODULE, gen_crc_err=%0d)", $time, gen_crc_err);
`DBG_TOP_WISHBONE_DEBUG_MODULE : $display("(%0t) Task module_select (DBG_TOP_WISHBONE_DEBUG_MODULE gen_crc_err=%0d)", $time, gen_crc_err);
default : $display("(%0t) Task module_select (ERROR!!! Unknown module selected)", $time);
endcase
`endif
tms<=#1 1'b1;
gen_clk(1);
tms<=#1 1'b0;
gen_clk(2); // we are in shiftDR
status = {`DBG_TOP_STATUS_LEN{1'b0}}; // Initialize status to all 0's
crc_out = {`DBG_TOP_CRC_LEN{1'b1}}; // Initialize outgoing CRC to all ff
tdi<=#1 1'b1; // module_select bit
calculate_crc(1'b1);
gen_clk(1);
for(i=`DBG_TOP_MODULE_ID_LENGTH -1; i>=0; i=i-1) // Shifting module ID
begin
tdi<=#1 data[i];
calculate_crc(data[i]);
gen_clk(1);
end
 
for(i=`DBG_TOP_CRC_LEN -1; i>=0; i=i-1)
begin
if (gen_crc_err & (i==0)) // Generate crc error at last crc bit
tdi<=#1 ~crc_out[i]; // error crc
else
tdi<=#1 crc_out[i]; // ok crc
gen_clk(1);
end
tdi<=#1 1'hz; // tri-state
crc_in = {`DBG_TOP_CRC_LEN{1'b1}}; // Initialize incoming CRC to all ff
for(i=`DBG_TOP_STATUS_LEN -1; i>=0; i=i-1)
begin
gen_clk(1); // Generating 1 clock to read out a status bit.
status[i] = tdo;
end
for(i=0; i<`DBG_TOP_CRC_LEN -1; i=i+1)
gen_clk(1);
tms<=#1 1'b1;
gen_clk(1); // to exit1_dr
if (~crc_match_in)
begin
$display("(%0t) Incoming CRC failed !!!", $time);
`ifdef DEBUG_INFO
$stop;
`endif
end
 
tms<=#1 1'b1;
gen_clk(1); // to update_dr
tms<=#1 1'b0;
gen_clk(1); // to run_test_idle
 
if (|status)
begin
$write("(*E) (%0t) Module select error: ", $time);
casex (status)
4'b1xxx : $display("CRC error !!!\n\n", $time);
4'bx1xx : $display("Non-existing module selected !!!\n\n", $time);
4'bxx1x : $display("Status[1] should be 1'b0 !!!\n\n", $time);
4'bxxx1 : $display("Status[0] should be 1'b0 !!!\n\n", $time);
endcase
`ifdef DEBUG_INFO
$stop;
`endif
end
end
endtask // module_select
 
 
 
// 32-bit write to the wishbone
task wb_write_32;
input [31:0] data;
input [`DBG_WB_ADR_LEN -1:0] addr;
input [`DBG_WB_LEN_LEN -1:0] length;
 
begin
data_storage[0] = data;
debug_wishbone_wr_comm(`DBG_WB_WRITE32, addr, length, 1'b0);
last_wb_cmd = `DBG_WB_WRITE32; last_wb_cmd_text = "DBG_WB_WRITE32";
length_global = length + 1;
debug_wishbone_go(1'b0, 1'b0);
//debug_wishbone_go(1'b1, 1'b0); // maybe causes underrun/overrun error when wait for WB ready?
if (length>3)
$display("WARNING: Only first data word is stored for writting ( See module %m)");
end
endtask
 
// block 32-bit write to the wishbone
// presumes data is already in data_storage[]
task wb_block_write_32;
input [`DBG_WB_ADR_LEN -1:0] addr;
input [`DBG_WB_LEN_LEN -1:0] length;
 
begin
 
debug_wishbone_wr_comm(`DBG_WB_WRITE32, addr, length-1, 1'b0);
 
last_wb_cmd = `DBG_WB_WRITE32; last_wb_cmd_text = "DBG_WB_WRITE32";
length_global = length; // number of bytes!
debug_wishbone_go(1'b0, 1'b0);
//debug_wishbone_go(1'b1, 1'b0); // maybe causes underrun/overrun error when wait for WB ready?
end
endtask
// 32-bit read from the wishbone
task wb_read_32;
 
output [31:0] data;
 
input [`DBG_WB_ADR_LEN -1:0] addr;
input [`DBG_WB_LEN_LEN -1:0] length;
 
begin
debug_wishbone_wr_comm(`DBG_WB_READ32, addr, length, 1'b0);
last_wb_cmd = `DBG_WB_READ32; last_wb_cmd_text = "DBG_WB_READ32";
length_global = length + 1;
//debug_wishbone_go(1'b0, 1'b0);
debug_wishbone_go(1'b1, 1'b0);
data = data_storage[0];
if (length>3)
$display("WARNING: Only first data word is stored for writting ( See module %m)");
end
endtask
 
 
// block 32-bit read from the wishbone
// assumes data will be stored into data_storage[]
task wb_block_read_32;
 
input [`DBG_WB_ADR_LEN -1:0] addr;
input [`DBG_WB_LEN_LEN -1:0] length;
 
begin
debug_wishbone_wr_comm(`DBG_WB_READ32, addr, length-1, 1'b0);
 
last_wb_cmd = `DBG_WB_READ32; last_wb_cmd_text = "DBG_WB_READ32";
length_global = length;
//debug_wishbone_go(1'b0, 1'b0);
debug_wishbone_go(1'b1, 1'b0);
end
endtask
 
// 16-bit write to the wishbone
task wb_write_16;
input [15:0] data;
input [`DBG_WB_ADR_LEN -1:0] addr;
input [`DBG_WB_LEN_LEN -1:0] length;
 
begin
data_storage[0] = {data, 16'h0};
debug_wishbone_wr_comm(`DBG_WB_WRITE16, addr, length, 1'b0);
last_wb_cmd = `DBG_WB_WRITE16; last_wb_cmd_text = "DBG_WB_WRITE16";
length_global = length + 1;
debug_wishbone_go(1'b0, 1'b0);
if (length>1)
$display("WARNING: Only first data half is stored for writting ( See module %m)");
end
endtask
 
 
 
// 8-bit write to the wishbone
task wb_write_8;
input [7:0] data;
input [`DBG_WB_ADR_LEN -1:0] addr;
input [`DBG_WB_LEN_LEN -1:0] length;
 
begin
data_storage[0] = {data, 24'h0};
debug_wishbone_wr_comm(`DBG_WB_WRITE8, addr, length, 1'b0);
last_wb_cmd = `DBG_WB_WRITE8; last_wb_cmd_text = "DBG_WB_WRITE8";
length_global = length + 1;
debug_wishbone_go(1'b0, 1'b0);
if (length>0)
$display("WARNING: Only first data byte is stored for writting ( See module %m)");
end
endtask
 
 
 
task debug_wishbone_wr_comm;
input [`DBG_WB_ACC_TYPE_LEN -1:0] acc_type;
input [`DBG_WB_ADR_LEN -1:0] addr;
input [`DBG_WB_LEN_LEN -1:0] length;
input gen_crc_err;
integer i;
reg [`DBG_WB_CMD_LEN -1:0] command;
begin
`ifdef DEBUG_INFO
$display("(%0t) Task debug_wishbone_wr_comm: ", $time);
`endif
command = `DBG_WB_WR_COMM;
tms<=#1 1'b1;
gen_clk(1);
tms<=#1 1'b0;
gen_clk(2); // we are in shiftDR
crc_out = {`DBG_WB_CRC_LEN{1'b1}}; // Initialize outgoing CRC to all ff
tdi<=#1 1'b0; // module_select bit = 0
calculate_crc(1'b0);
gen_clk(1);
for(i=`DBG_WB_CMD_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 command[i]; // command
calculate_crc(command[i]);
gen_clk(1);
end
for(i=`DBG_WB_ACC_TYPE_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 acc_type[i]; // command
calculate_crc(acc_type[i]);
gen_clk(1);
end
for(i=`DBG_WB_ADR_LEN -1; i>=0; i=i-1) // address
begin
tdi<=#1 addr[i];
calculate_crc(addr[i]);
gen_clk(1);
end
for(i=`DBG_WB_LEN_LEN -1; i>=0; i=i-1) // length
begin
tdi<=#1 length[i];
calculate_crc(length[i]);
gen_clk(1);
end
for(i=`DBG_WB_CRC_LEN -1; i>=0; i=i-1)
begin
if (gen_crc_err & (i==0)) // Generate crc error at last crc bit
tdi<=#1 ~crc_out[i]; // error crc
else
tdi<=#1 crc_out[i]; // ok crc
gen_clk(1);
end
tdi<=#1 1'hz;
crc_in = {`DBG_WB_CRC_LEN{1'b1}}; // Initialize incoming CRC to all ff
for(i=`DBG_WB_STATUS_LEN -1; i>=0; i=i-1)
begin
gen_clk(1); // Generating clock to read out a status bit.
status_wb[i] = tdo;
end
if (|status_wb)
begin
$write("(*E) (%0t) debug_wishbone_wr_comm error: ", $time);
casex (status_wb)
4'b1xxx : $display("CRC error !!!\n\n", $time);
4'bx1xx : $display("Unknown command !!!\n\n", $time);
4'bxx1x : $display("WISHBONE error !!!\n\n", $time);
4'bxxx1 : $display("Overrun/Underrun !!!\n\n", $time);
endcase
`ifdef DEBUG_INFO
$stop;
`endif
end
for(i=0; i<`DBG_WB_CRC_LEN -1; i=i+1) // Getting in the CRC
begin
gen_clk(1);
end
tms<=#1 1'b1;
gen_clk(1); // to exit1_dr
if (~crc_match_in)
begin
$display("(%0t) Incoming CRC failed !!!", $time);
`ifdef DEBUG_INFO
$stop;
`endif
end
 
tms<=#1 1'b1;
gen_clk(1); // to update_dr
tms<=#1 1'b0;
gen_clk(1); // to run_test_idle
end
endtask // debug_wishbone_wr_comm
 
 
 
task debug_wishbone_go;
 
input wait_for_wb_ready;
input gen_crc_err;
integer i;
reg [4:0] bit_pointer;
integer word_pointer;
reg [31:0] tmp_data;
reg [`DBG_WB_CMD_LEN -1:0] command;
begin
`ifdef DEBUG_INFO
$display("(%0t) Task debug_wishbone_go (previous command was %0s): ", $time, last_wb_cmd_text);
`endif
 
command = `DBG_WB_GO;
word_pointer = 0;
tms<=#1 1'b1;
gen_clk(1);
tms<=#1 1'b0;
gen_clk(2); // we are in shiftDR
crc_out = {`DBG_WB_CRC_LEN{1'b1}}; // Initialize outgoing CRC to all ff
tdi<=#1 1'b0; // module_select bit = 0
calculate_crc(1'b0);
gen_clk(1);
for(i=`DBG_WB_CMD_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 command[i]; // command
calculate_crc(command[i]);
gen_clk(1);
end
// W R I T E
if (
(last_wb_cmd == `DBG_WB_WRITE8) | (last_wb_cmd == `DBG_WB_WRITE16) |
(last_wb_cmd == `DBG_WB_WRITE32)
) // When WB_WRITEx was previously activated, data needs to be shifted.
begin
for (i=0; i<((length_global) << 3); i=i+1)
begin
if ((!(i%32)) && (i>0))
begin
word_pointer = word_pointer + 1;
end
tmp_data = data_storage[word_pointer];
bit_pointer = 31-i[4:0];
tdi<=#1 tmp_data[bit_pointer];
calculate_crc(tmp_data[bit_pointer]);
gen_clk(1);
 
end
end
for(i=`DBG_WB_CRC_LEN -1; i>=1; i=i-1)
begin
tdi<=#1 crc_out[i];
gen_clk(1);
end
if (gen_crc_err) // Generate crc error at last crc bit
tdi<=#1 ~crc_out[0]; // error crc
else
tdi<=#1 crc_out[0]; // ok crc
if (wait_for_wb_ready)
begin
tms<=#1 1'b1;
gen_clk(1); // to exit1_dr. Last CRC is shifted on this clk
tms<=#1 1'b0;
gen_clk(1); // to pause_dr
#2; // wait a bit for tdo to activate
while (tdo) // waiting for wb to send "ready"
begin
gen_clk(1); // staying in pause_dr
end
tms<=#1 1'b1;
gen_clk(1); // to exit2_dr
tms<=#1 1'b0;
gen_clk(1); // to shift_dr
end
else
begin
gen_clk(1); // Last CRC is shifted on this clk
end
tdi<=#1 1'hz;
 
// R E A D
crc_in = {`DBG_WB_CRC_LEN{1'b1}}; // Initialize incoming CRC to all ff
if (
(last_wb_cmd == `DBG_WB_READ8) | (last_wb_cmd == `DBG_WB_READ16) |
(last_wb_cmd == `DBG_WB_READ32)
) // When WB_READx was previously activated, data needs to be shifted.
begin
`ifdef DEBUG_INFO
$display("\t\tGenerating %0d clocks to read %0d data bytes.", length_global<<3, length_global);
`endif
word_pointer = 0; // Reset pointer
for (i=0; i<(length_global<<3); i=i+1)
begin
gen_clk(1);
if (i[4:0] == 31) // Latching data
begin
data_storage[word_pointer] = in_data_be;
`ifdef DEBUG_INFO
$display("\t\tin_data_be = 0x%x", in_data_be);
`endif
word_pointer = word_pointer + 1;
end
end
end
for(i=`DBG_WB_STATUS_LEN -1; i>=0; i=i-1)
begin
gen_clk(1); // Generating clock to read out a status bit.
status_wb[i] = tdo;
end
if (|status_wb)
begin
$write("(*E) (%0t) debug_wishbone_go error: ", $time);
casex (status_wb)
4'b1xxx : $display("CRC error !!!\n\n", $time);
4'bx1xx : $display("Unknown command !!!\n\n", $time);
4'bxx1x : $display("WISHBONE error !!!\n\n", $time);
4'bxxx1 : $display("Overrun/Underrun !!!\n\n", $time);
endcase
`ifdef DEBUG_INFO
$stop;
`endif
end
for(i=0; i<`DBG_WB_CRC_LEN -1; i=i+1) // Getting in the CRC
begin
gen_clk(1);
end
tms<=#1 1'b1;
gen_clk(1); // to exit1_dr
if (~crc_match_in)
begin
$display("(%0t) Incoming CRC failed !!!", $time);
`ifdef DEBUG_INFO
$stop;
`endif
end
 
tms<=#1 1'b1;
gen_clk(1); // to update_dr
tms<=#1 1'b0;
gen_clk(1); // to run_test_idle
end
endtask // debug_wishbone_go
 
 
 
task debug_cpu_wr_ctrl;
input [`DBG_CPU_DR_LEN -1:0] data;
input [99:0] text;
integer i;
reg [`DBG_CPU_CMD_LEN -1:0] command;
begin
test_text = text;
`ifdef DEBUG_INFO
$display("(%0t) Task debug_cpu_wr_ctrl (data=0x%0x (%0s))", $time, data, text);
`endif
command = `DBG_CPU_WR_CTRL;
tms<=#1 1'b1;
gen_clk(1);
tms<=#1 1'b0;
gen_clk(2); // we are in shiftDR
crc_out = {`DBG_CPU_CRC_LEN{1'b1}}; // Initialize outgoing CRC to all ff
tdi<=#1 1'b0; // module_select bit = 0
calculate_crc(1'b0);
gen_clk(1);
for(i=`DBG_CPU_CMD_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 command[i]; // command
calculate_crc(command[i]);
gen_clk(1);
end
 
for(i=`DBG_CPU_CTRL_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 data[i]; // data (used cotrol bits
calculate_crc(data[i]);
gen_clk(1);
end
 
for(i=`DBG_CPU_DR_LEN - `DBG_CPU_CTRL_LEN -1; i>=0; i=i-1) // unused control bits
begin
tdi<=#1 1'b0;
calculate_crc(1'b0);
gen_clk(1);
end
for(i=`DBG_CPU_CRC_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 crc_out[i]; // ok crc
gen_clk(1);
end
tdi<=#1 1'hz;
crc_in = {`DBG_CPU_CRC_LEN{1'b1}}; // Initialize incoming CRC to all ff
for(i=`DBG_CPU_STATUS_LEN -1; i>=0; i=i-1)
begin
gen_clk(1); // Generating clock to read out a status bit.
status_cpu[i] = tdo;
end
if (|status_cpu)
begin
$write("(*E) (%0t) debug_cpu_wr_ctrl error: ", $time);
casex (status_cpu)
4'b1xxx : $display("CRC error !!!\n\n", $time);
4'bx1xx : $display("??? error !!!\n\n", $time);
4'bxx1x : $display("??? error !!!\n\n", $time);
4'bxxx1 : $display("??? error !!!\n\n", $time);
endcase
`ifdef DEBUG_INFO
$stop;
`endif
end
for(i=0; i<`DBG_CPU_CRC_LEN -1; i=i+1) // Getting in the CRC
begin
gen_clk(1);
end
tms<=#1 1'b1;
gen_clk(1); // to exit1_dr
if (~crc_match_in)
begin
$display("(%0t) Incoming CRC failed !!!", $time);
`ifdef DEBUG_INFO
$stop;
`endif
end
 
tms<=#1 1'b1;
gen_clk(1); // to update_dr
tms<=#1 1'b0;
gen_clk(1); // to run_test_idle
end
endtask // debug_cpu_wr_ctrl
 
task debug_cpu_rd_ctrl;
output [`DBG_CPU_DR_LEN -1:0] data;
//input [99:0] text;
integer i;
reg [`DBG_CPU_CMD_LEN -1:0] command;
begin
 
`ifdef DEBUG_INFO
$display("(%0t) Task debug_cpu_rd_ctrl", $time);
`endif
command = `DBG_CPU_RD_CTRL;
tms<=#1 1'b1;
gen_clk(1);
tms<=#1 1'b0;
gen_clk(2); // we are in shiftDR
crc_out = {`DBG_CPU_CRC_LEN{1'b1}}; // Initialize outgoing CRC to all ff
tdi<=#1 1'b0; // module_select bit = 0
calculate_crc(1'b0);
gen_clk(1);
for(i=`DBG_CPU_CMD_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 command[i]; // command
calculate_crc(command[i]);
gen_clk(1);
end
for(i=`DBG_CPU_CRC_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 crc_out[i]; // ok crc
gen_clk(1);
end
tdi<=#1 1'hz;
crc_in = {`DBG_CPU_CRC_LEN{1'b1}}; // Initialize incoming CRC to all ff
// Read incoming debug ctrl data (52 bits)
//cpu_ctrl_val[1:0];
gen_clk(1);
//cpu_ctrl_val[0] <= #1 tdo; // cpu reset bit
data[0] <= #1 tdo; // cpu reset bit
gen_clk(1);
//cpu_ctrl_val[1] <= #1 tdo; // cpu stall bit
data[1] <= #1 tdo; // cpu stall bit
for(i=`DBG_CPU_DR_LEN - `DBG_CPU_CTRL_LEN -1; i>=0; i=i-1) // unused control bits
begin
gen_clk(1);
end
for(i=`DBG_CPU_STATUS_LEN -1; i>=0; i=i-1)
begin
gen_clk(1); // Generating clock to read out a status bit.
status_cpu[i] = tdo;
end
if (|status_cpu)
begin
$write("(*E) (%0t) debug_cpu_wr_ctrl error: ", $time);
casex (status_cpu)
4'b1xxx : $display("CRC error !!!\n\n", $time);
4'bx1xx : $display("??? error !!!\n\n", $time);
4'bxx1x : $display("??? error !!!\n\n", $time);
4'bxxx1 : $display("??? error !!!\n\n", $time);
endcase // casex (status_cpu)
end
for(i=0; i<`DBG_CPU_CRC_LEN -1; i=i+1) // Getting in the CRC
begin
gen_clk(1);
end
tms<=#1 1'b1;
gen_clk(1); // to exit1_dr
if (~crc_match_in)
begin
$display("(%0t) Incoming CRC failed !!!", $time);
 
end
 
tms<=#1 1'b1;
gen_clk(1); // to update_dr
tms<=#1 1'b0;
gen_clk(1); // to run_test_idle
end
endtask // debug_cpu_rd_ctrl
 
 
// 32-bit read from cpu
task cpu_read_32;
output [31:0] data;
input [`DBG_WB_ADR_LEN -1:0] addr;
input [`DBG_WB_LEN_LEN -1:0] length;
 
reg [31:0] tmp;
 
begin
debug_cpu_wr_comm(`DBG_CPU_READ, addr, length, 1'b0);
last_cpu_cmd = `DBG_CPU_READ; last_cpu_cmd_text = "DBG_CPU_READ";
length_global = length + 1;
debug_cpu_go(1'b0, 1'b0);
data = data_storage[0];
if (length>3)
$display("WARNING: Only first data word is returned( See module %m.)");
end
endtask
 
 
 
// 32-bit write to cpu
task cpu_write_32;
input [31:0] data;
input [`DBG_WB_ADR_LEN -1:0] addr;
input [`DBG_WB_LEN_LEN -1:0] length;
 
reg [31:0] tmp;
 
begin
debug_cpu_wr_comm(`DBG_CPU_WRITE, addr, length, 1'b0);
last_cpu_cmd = `DBG_CPU_WRITE; last_cpu_cmd_text = "DBG_CPU_WRITE";
length_global = length + 1;
data_storage[0] = data;
debug_cpu_go(1'b0, 1'b0);
if (length>3)
$display("WARNING: Only first data word is stored for writting ( See module %m)");
end
endtask
 
 
 
task debug_cpu_wr_comm;
input [`DBG_CPU_ACC_TYPE_LEN -1:0] acc_type;
input [`DBG_CPU_ADR_LEN -1:0] addr;
input [`DBG_CPU_LEN_LEN -1:0] length;
input gen_crc_err;
integer i;
reg [`DBG_CPU_CMD_LEN -1:0] command;
begin
`ifdef DEBUG_INFO
$display("(%0t) Task debug_cpu_wr_comm: ", $time);
`endif
 
command = `DBG_CPU_WR_COMM;
tms<=#1 1'b1;
gen_clk(1);
tms<=#1 1'b0;
gen_clk(2); // we are in shiftDR
 
crc_out = {`DBG_CPU_CRC_LEN{1'b1}}; // Initialize outgoing CRC to all ff
 
tdi<=#1 1'b0; // module_select bit = 0
calculate_crc(1'b0);
gen_clk(1);
 
for(i=`DBG_CPU_CMD_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 command[i]; // command
calculate_crc(command[i]);
gen_clk(1);
end
 
for(i=`DBG_CPU_ACC_TYPE_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 acc_type[i]; // command
calculate_crc(acc_type[i]);
gen_clk(1);
end
 
for(i=`DBG_CPU_ADR_LEN -1; i>=0; i=i-1) // address
begin
tdi<=#1 addr[i];
calculate_crc(addr[i]);
gen_clk(1);
end
for(i=`DBG_CPU_LEN_LEN -1; i>=0; i=i-1) // length
begin
tdi<=#1 length[i];
calculate_crc(length[i]);
gen_clk(1);
end
 
for(i=`DBG_CPU_CRC_LEN -1; i>=0; i=i-1)
begin
if (gen_crc_err & (i==0)) // Generate crc error at last crc bit
tdi<=#1 ~crc_out[i]; // error crc
else
tdi<=#1 crc_out[i]; // ok crc
 
gen_clk(1);
end
 
tdi<=#1 1'hz;
 
crc_in = {`DBG_CPU_CRC_LEN{1'b1}}; // Initialize incoming CRC to all ff
 
for(i=`DBG_CPU_STATUS_LEN -1; i>=0; i=i-1)
begin
gen_clk(1); // Generating clock to read out a status bit.
status_cpu[i] = tdo;
end
 
if (|status_cpu)
begin
$write("(*E) (%0t) debug_cpu_wr_comm error: ", $time);
casex (status_cpu)
4'b1xxx : $display("CRC error !!!\n\n", $time);
4'bx1xx : $display("Unknown command !!!\n\n", $time);
4'bxx1x : $display("??? error !!!\n\n", $time);
4'bxxx1 : $display("Overrun/Underrun !!!\n\n", $time);
endcase
`ifdef DEBUG_INFO
$stop;
`endif
end
 
 
for(i=0; i<`DBG_CPU_CRC_LEN -1; i=i+1) // Getting in the CRC
begin
gen_clk(1);
end
 
tms<=#1 1'b1;
gen_clk(1); // to exit1_dr
 
if (~crc_match_in)
begin
$display("(%0t) Incoming CRC failed !!!", $time);
`ifdef DEBUG_INFO
$stop;
`endif
end
 
tms<=#1 1'b1;
gen_clk(1); // to update_dr
tms<=#1 1'b0;
gen_clk(1); // to run_test_idle
end
endtask // debug_cpu_wr_comm
 
 
 
task debug_cpu_go;
input wait_for_cpu_ready;
input gen_crc_err;
integer i;
reg [4:0] bit_pointer;
integer word_pointer;
reg [31:0] tmp_data;
reg [`DBG_CPU_CMD_LEN -1:0] command;
 
begin
`ifdef DEBUG_INFO
$display("(%0t) Task debug_cpu_go (previous command was %0s): ", $time, last_cpu_cmd_text);
`endif
command = `DBG_CPU_GO;
word_pointer = 0;
 
tms<=#1 1'b1;
gen_clk(1);
tms<=#1 1'b0;
gen_clk(2); // we are in shiftDR
 
crc_out = {`DBG_CPU_CRC_LEN{1'b1}}; // Initialize outgoing CRC to all ff
 
tdi<=#1 1'b0; // module_select bit = 0
calculate_crc(1'b0);
gen_clk(1);
 
for(i=`DBG_CPU_CMD_LEN -1; i>=0; i=i-1)
begin
tdi<=#1 command[i]; // command
calculate_crc(command[i]);
gen_clk(1);
end
 
 
if (last_cpu_cmd == `DBG_CPU_WRITE) // When DBG_CPU_WRITE was previously activated, data needs to be shifted.
begin
for (i=0; i<((length_global) << 3); i=i+1)
begin
tmp_data = data_storage[word_pointer];
if ((!(i%32)) && (i>0))
begin
word_pointer = word_pointer + 1;
end
bit_pointer = 31-i[4:0];
tdi<=#1 tmp_data[bit_pointer];
calculate_crc(tmp_data[bit_pointer]);
gen_clk(1);
 
end
end
 
for(i=`DBG_CPU_CRC_LEN -1; i>=1; i=i-1)
begin
tdi<=#1 crc_out[i];
gen_clk(1);
end
 
if (gen_crc_err) // Generate crc error at last crc bit
tdi<=#1 ~crc_out[0]; // error crc
else
tdi<=#1 crc_out[0]; // ok crc
 
if (wait_for_cpu_ready)
begin
tms<=#1 1'b1;
gen_clk(1); // to exit1_dr. Last CRC is shifted on this clk
tms<=#1 1'b0;
gen_clk(1); // to pause_dr
 
#2; // wait a bit for tdo to activate
while (tdo) // waiting for wb to send "ready"
begin
gen_clk(1); // staying in pause_dr
end
tms<=#1 1'b1;
gen_clk(1); // to exit2_dr
tms<=#1 1'b0;
gen_clk(1); // to shift_dr
end
else
begin
gen_clk(1); // Last CRC is shifted on this clk
end
 
 
tdi<=#1 1'hz;
crc_in = {`DBG_CPU_CRC_LEN{1'b1}}; // Initialize incoming CRC to all ff
 
if (last_cpu_cmd == `DBG_CPU_READ) // When DBG_CPU_READ was previously activated, data needs to be shifted.
begin
`ifdef DEBUG_INFO
$display("\t\tGenerating %0d clocks to read %0d data bytes.", length_global<<3, length_global);
`endif
word_pointer = 0; // Reset pointer
for (i=0; i<(length_global<<3); i=i+1)
begin
gen_clk(1);
if (i[4:0] == 31) // Latching data
begin
data_storage[word_pointer] = in_data_be;
`ifdef DEBUG_INFO
$display("\t\tin_data_be = 0x%x", in_data_be);
`endif
word_pointer = word_pointer + 1;
end
end
end
 
 
for(i=`DBG_CPU_STATUS_LEN -1; i>=0; i=i-1)
begin
gen_clk(1); // Generating clock to read out a status bit.
status_cpu[i] = tdo;
end
 
if (|status_cpu)
begin
$write("(*E) (%0t) debug_cpu_go error: ", $time);
casex (status_cpu)
4'b1xxx : $display("CRC error !!!\n\n", $time);
4'bx1xx : $display("Unknown command !!!\n\n", $time);
4'bxx1x : $display("??? error !!!\n\n", $time);
4'bxxx1 : $display("Overrun/Underrun !!!\n\n", $time);
endcase
$stop;
end
 
 
for(i=0; i<`DBG_CPU_CRC_LEN -1; i=i+1) // Getting in the CRC
begin
gen_clk(1);
end
 
tms<=#1 1'b1;
gen_clk(1); // to exit1_dr
 
if (~crc_match_in)
begin
$display("(%0t) Incoming CRC failed !!!", $time);
$stop;
end
 
tms<=#1 1'b1;
gen_clk(1); // to update_dr
tms<=#1 1'b0;
gen_clk(1); // to run_test_idle
end
endtask // debug_cpu_go
 
 
 
 
// Calculating outgoing CRC
task calculate_crc;
input data;
begin
crc_out[0] <= #1 data ^ crc_out[31];
crc_out[1] <= #1 data ^ crc_out[0] ^ crc_out[31];
crc_out[2] <= #1 data ^ crc_out[1] ^ crc_out[31];
crc_out[3] <= #1 crc_out[2];
crc_out[4] <= #1 data ^ crc_out[3] ^ crc_out[31];
crc_out[5] <= #1 data ^ crc_out[4] ^ crc_out[31];
crc_out[6] <= #1 crc_out[5];
crc_out[7] <= #1 data ^ crc_out[6] ^ crc_out[31];
crc_out[8] <= #1 data ^ crc_out[7] ^ crc_out[31];
crc_out[9] <= #1 crc_out[8];
crc_out[10] <= #1 data ^ crc_out[9] ^ crc_out[31];
crc_out[11] <= #1 data ^ crc_out[10] ^ crc_out[31];
crc_out[12] <= #1 data ^ crc_out[11] ^ crc_out[31];
crc_out[13] <= #1 crc_out[12];
crc_out[14] <= #1 crc_out[13];
crc_out[15] <= #1 crc_out[14];
crc_out[16] <= #1 data ^ crc_out[15] ^ crc_out[31];
crc_out[17] <= #1 crc_out[16];
crc_out[18] <= #1 crc_out[17];
crc_out[19] <= #1 crc_out[18];
crc_out[20] <= #1 crc_out[19];
crc_out[21] <= #1 crc_out[20];
crc_out[22] <= #1 data ^ crc_out[21] ^ crc_out[31];
crc_out[23] <= #1 data ^ crc_out[22] ^ crc_out[31];
crc_out[24] <= #1 crc_out[23];
crc_out[25] <= #1 crc_out[24];
crc_out[26] <= #1 data ^ crc_out[25] ^ crc_out[31];
crc_out[27] <= #1 crc_out[26];
crc_out[28] <= #1 crc_out[27];
crc_out[29] <= #1 crc_out[28];
crc_out[30] <= #1 crc_out[29];
crc_out[31] <= #1 crc_out[30];
end
endtask // calculate_crc
 
 
// Calculating and checking input CRC
always @(posedge tck)
begin
crc_in[0] <= #1 tdo ^ crc_in[31];
crc_in[1] <= #1 tdo ^ crc_in[0] ^ crc_in[31];
crc_in[2] <= #1 tdo ^ crc_in[1] ^ crc_in[31];
crc_in[3] <= #1 crc_in[2];
crc_in[4] <= #1 tdo ^ crc_in[3] ^ crc_in[31];
crc_in[5] <= #1 tdo ^ crc_in[4] ^ crc_in[31];
crc_in[6] <= #1 crc_in[5];
crc_in[7] <= #1 tdo ^ crc_in[6] ^ crc_in[31];
crc_in[8] <= #1 tdo ^ crc_in[7] ^ crc_in[31];
crc_in[9] <= #1 crc_in[8];
crc_in[10] <= #1 tdo ^ crc_in[9] ^ crc_in[31];
crc_in[11] <= #1 tdo ^ crc_in[10] ^ crc_in[31];
crc_in[12] <= #1 tdo ^ crc_in[11] ^ crc_in[31];
crc_in[13] <= #1 crc_in[12];
crc_in[14] <= #1 crc_in[13];
crc_in[15] <= #1 crc_in[14];
crc_in[16] <= #1 tdo ^ crc_in[15] ^ crc_in[31];
crc_in[17] <= #1 crc_in[16];
crc_in[18] <= #1 crc_in[17];
crc_in[19] <= #1 crc_in[18];
crc_in[20] <= #1 crc_in[19];
crc_in[21] <= #1 crc_in[20];
crc_in[22] <= #1 tdo ^ crc_in[21] ^ crc_in[31];
crc_in[23] <= #1 tdo ^ crc_in[22] ^ crc_in[31];
crc_in[24] <= #1 crc_in[23];
crc_in[25] <= #1 crc_in[24];
crc_in[26] <= #1 tdo ^ crc_in[25] ^ crc_in[31];
crc_in[27] <= #1 crc_in[26];
crc_in[28] <= #1 crc_in[27];
crc_in[29] <= #1 crc_in[28];
crc_in[30] <= #1 crc_in[29];
crc_in[31] <= #1 crc_in[30];
end
assign crc_match_in = crc_in == 32'h0;
 
 
endmodule // vpi_debug_module

powered by: WebSVN 2.1.0

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