aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHsiangkai Wang <hsiangkai@gmail.com>2013-08-27 16:10:16 +0800
committerSpencer Oliver <spen@spen-soft.co.uk>2013-09-13 19:37:23 +0000
commit9288a59aa1bad76c8ae91c00b876fe24508476fd (patch)
treec8374152da6f3d91f470d8ec2c474b1c50e69b69 /src
parent6d86ded4dbc7fb44cc659c6c39d6507752133c6b (diff)
nds32: support Andes profiling function
Change-Id: Ibc45ec5777d6841956c02de6b4ae8e74c2a6de37 Signed-off-by: Hsiangkai Wang <hsiangkai@gmail.com> Reviewed-on: http://openocd.zylin.com/1585 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Diffstat (limited to 'src')
-rw-r--r--src/jtag/aice/aice_port.h4
-rw-r--r--src/jtag/aice/aice_usb.c166
-rw-r--r--src/target/nds32.c19
-rw-r--r--src/target/nds32.h2
-rw-r--r--src/target/nds32_v3.c2
5 files changed, 192 insertions, 1 deletions
diff --git a/src/jtag/aice/aice_port.h b/src/jtag/aice/aice_port.h
index 8f3e8551..35bc61c9 100644
--- a/src/jtag/aice/aice_port.h
+++ b/src/jtag/aice/aice_port.h
@@ -218,6 +218,10 @@ struct aice_port_api_s {
/** */
int (*set_data_endian)(enum aice_target_endian target_data_endian);
+
+ /** */
+ int (*profiling)(uint32_t interval, uint32_t iteration,
+ uint32_t reg_no, uint32_t *samples, uint32_t *num_samples);
};
#define AICE_PORT_UNKNOWN 0
diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c
index 30509d3b..f25a0f5c 100644
--- a/src/jtag/aice/aice_usb.c
+++ b/src/jtag/aice/aice_usb.c
@@ -390,7 +390,7 @@ static uint32_t usb_out_packets_buffer_length;
static uint32_t usb_in_packets_buffer_length;
static enum aice_command_mode aice_command_mode;
-extern int aice_batch_buffer_write(uint8_t buf_index, const uint8_t *word,
+static int aice_batch_buffer_write(uint8_t buf_index, const uint8_t *word,
uint32_t num_of_words);
static int aice_usb_packet_flush(void)
@@ -3788,6 +3788,168 @@ static int aice_usb_set_data_endian(enum aice_target_endian target_data_endian)
return ERROR_OK;
}
+static int fill_profiling_batch_commands(uint32_t reg_no)
+{
+ uint32_t dim_instructions[4];
+
+ aice_usb_set_command_mode(AICE_COMMAND_MODE_BATCH);
+
+ /* halt */
+ if (aice_write_misc(current_target_id, NDS_EDM_MISC_EDM_CMDR, 0) != ERROR_OK)
+ return ERROR_FAIL;
+
+ /* backup $r0 */
+ dim_instructions[0] = MTSR_DTR(0);
+ dim_instructions[1] = DSB;
+ dim_instructions[2] = NOP;
+ dim_instructions[3] = BEQ_MINUS_12;
+ if (aice_write_dim(current_target_id, dim_instructions, 4) != ERROR_OK)
+ return ERROR_FAIL;
+ aice_read_dtr_to_buffer(current_target_id, AICE_BATCH_DATA_BUFFER_0);
+
+ /* get samples */
+ if (NDS32_REG_TYPE_GPR == nds32_reg_type(reg_no)) {
+ /* general registers */
+ dim_instructions[0] = MTSR_DTR(reg_no);
+ dim_instructions[1] = DSB;
+ dim_instructions[2] = NOP;
+ dim_instructions[3] = BEQ_MINUS_12;
+ } else if (NDS32_REG_TYPE_SPR == nds32_reg_type(reg_no)) {
+ /* user special registers */
+ dim_instructions[0] = MFUSR_G0(0, nds32_reg_sr_index(reg_no));
+ dim_instructions[1] = MTSR_DTR(0);
+ dim_instructions[2] = DSB;
+ dim_instructions[3] = BEQ_MINUS_12;
+ } else { /* system registers */
+ dim_instructions[0] = MFSR(0, nds32_reg_sr_index(reg_no));
+ dim_instructions[1] = MTSR_DTR(0);
+ dim_instructions[2] = DSB;
+ dim_instructions[3] = BEQ_MINUS_12;
+ }
+ if (aice_write_dim(current_target_id, dim_instructions, 4) != ERROR_OK)
+ return ERROR_FAIL;
+ aice_read_dtr_to_buffer(current_target_id, AICE_BATCH_DATA_BUFFER_1);
+
+ /* restore $r0 */
+ aice_write_dtr_from_buffer(current_target_id, AICE_BATCH_DATA_BUFFER_0);
+ dim_instructions[0] = MFSR_DTR(0);
+ dim_instructions[1] = DSB;
+ dim_instructions[2] = NOP;
+ dim_instructions[3] = IRET; /* free run */
+ if (aice_write_dim(current_target_id, dim_instructions, 4) != ERROR_OK)
+ return ERROR_FAIL;
+
+ aice_command_mode = AICE_COMMAND_MODE_NORMAL;
+
+ /* use BATCH_BUFFER_WRITE to fill command-batch-buffer */
+ if (aice_batch_buffer_write(AICE_BATCH_COMMAND_BUFFER_0,
+ usb_out_packets_buffer,
+ (usb_out_packets_buffer_length + 3) / 4) != ERROR_OK)
+ return ERROR_FAIL;
+
+ usb_out_packets_buffer_length = 0;
+ usb_in_packets_buffer_length = 0;
+
+ return ERROR_OK;
+}
+
+static int aice_usb_profiling(uint32_t interval, uint32_t iteration,
+ uint32_t reg_no, uint32_t *samples, uint32_t *num_samples)
+{
+ uint32_t iteration_count;
+ uint32_t this_iteration;
+ int retval = ERROR_OK;
+ const uint32_t MAX_ITERATION = 250;
+
+ *num_samples = 0;
+
+ /* init DIM size */
+ if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_DIM_SIZE, 4) != ERROR_OK)
+ return ERROR_FAIL;
+
+ /* Use AICE_BATCH_DATA_BUFFER_0 to read/write $DTR.
+ * Set it to circular buffer */
+ if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_DATA_BUF0_CTRL, 0xC0000) != ERROR_OK)
+ return ERROR_FAIL;
+
+ fill_profiling_batch_commands(reg_no);
+
+ iteration_count = 0;
+ while (iteration_count < iteration) {
+ if (iteration - iteration_count < MAX_ITERATION)
+ this_iteration = iteration - iteration_count;
+ else
+ this_iteration = MAX_ITERATION;
+
+ /* set number of iterations */
+ uint32_t val_iteration;
+ val_iteration = interval << 16 | this_iteration;
+ if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_ITERATION,
+ val_iteration) != ERROR_OK) {
+ retval = ERROR_FAIL;
+ goto end_profiling;
+ }
+
+ /* init AICE_WRITE_CTRL_BATCH_DATA_BUF1_CTRL to store $PC */
+ if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_DATA_BUF1_CTRL,
+ 0x40000) != ERROR_OK) {
+ retval = ERROR_FAIL;
+ goto end_profiling;
+ }
+
+ aice_usb_run();
+
+ /* enable BATCH command */
+ if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_CTRL,
+ 0x80000000) != ERROR_OK) {
+ aice_usb_halt();
+ retval = ERROR_FAIL;
+ goto end_profiling;
+ }
+
+ /* wait a while (AICE bug, workaround) */
+ alive_sleep(this_iteration);
+
+ /* check status */
+ uint32_t i;
+ uint32_t batch_status;
+
+ i = 0;
+ while (1) {
+ aice_read_ctrl(AICE_READ_CTRL_BATCH_STATUS, &batch_status);
+
+ if (batch_status & 0x1) {
+ break;
+ } else if (batch_status & 0xE) {
+ aice_usb_halt();
+ retval = ERROR_FAIL;
+ goto end_profiling;
+ }
+
+ if ((i % 30) == 0)
+ keep_alive();
+
+ i++;
+ }
+
+ aice_usb_halt();
+
+ /* get samples from batch data buffer */
+ if (aice_batch_buffer_read(AICE_BATCH_DATA_BUFFER_1,
+ samples + iteration_count, this_iteration) != ERROR_OK) {
+ retval = ERROR_FAIL;
+ goto end_profiling;
+ }
+
+ iteration_count += this_iteration;
+ }
+
+end_profiling:
+ *num_samples = iteration_count;
+
+ return retval;
+}
+
/** */
struct aice_port_api_s aice_usb_api = {
/** */
@@ -3858,4 +4020,6 @@ struct aice_port_api_s aice_usb_api = {
.set_count_to_check_dbger = aice_usb_set_count_to_check_dbger,
/** */
.set_data_endian = aice_usb_set_data_endian,
+ /** */
+ .profiling = aice_usb_profiling,
};
diff --git a/src/target/nds32.c b/src/target/nds32.c
index 11bb01d0..49fde0c9 100644
--- a/src/target/nds32.c
+++ b/src/target/nds32.c
@@ -2455,6 +2455,25 @@ int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, b
return ERROR_OK;
}
+int nds32_profiling(struct target *target, uint32_t *samples,
+ uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
+{
+ /* sample $PC every 10 milliseconds */
+ uint32_t iteration = seconds * 100;
+ struct aice_port_s *aice = target_to_aice(target);
+ struct nds32 *nds32 = target_to_nds32(target);
+
+ if (max_num_samples < iteration)
+ iteration = max_num_samples;
+
+ int pc_regnum = nds32->register_map(nds32, PC);
+ aice->port->api->profiling(10, iteration, pc_regnum, samples, num_samples);
+
+ register_cache_invalidate(nds32->core_cache);
+
+ return ERROR_OK;
+}
+
int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address,
uint32_t size, const uint8_t *buffer)
{
diff --git a/src/target/nds32.h b/src/target/nds32.h
index 8acd915f..304fc35f 100644
--- a/src/target/nds32.h
+++ b/src/target/nds32.h
@@ -422,6 +422,8 @@ extern int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address,
extern int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
extern int nds32_reset_halt(struct nds32 *nds32);
extern int nds32_login(struct nds32 *nds32);
+extern int nds32_profiling(struct target *target, uint32_t *samples,
+ uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
/** Convert target handle to generic Andes target state handle. */
static inline struct nds32 *target_to_nds32(struct target *target)
diff --git a/src/target/nds32_v3.c b/src/target/nds32_v3.c
index 766e5ccb..5996a908 100644
--- a/src/target/nds32_v3.c
+++ b/src/target/nds32_v3.c
@@ -523,4 +523,6 @@ struct target_type nds32_v3_target = {
.get_gdb_fileio_info = nds32_get_gdb_fileio_info,
.gdb_fileio_end = nds32_gdb_fileio_end,
+
+ .profiling = nds32_profiling,
};