From 9288a59aa1bad76c8ae91c00b876fe24508476fd Mon Sep 17 00:00:00 2001 From: Hsiangkai Wang Date: Tue, 27 Aug 2013 16:10:16 +0800 Subject: [PATCH] nds32: support Andes profiling function Change-Id: Ibc45ec5777d6841956c02de6b4ae8e74c2a6de37 Signed-off-by: Hsiangkai Wang Reviewed-on: http://openocd.zylin.com/1585 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/aice/aice_port.h | 4 + src/jtag/aice/aice_usb.c | 166 +++++++++++++++++++++++++++++++++++++- src/target/nds32.c | 19 +++++ src/target/nds32.h | 2 + src/target/nds32_v3.c | 2 + 5 files changed, 192 insertions(+), 1 deletion(-) diff --git a/src/jtag/aice/aice_port.h b/src/jtag/aice/aice_port.h index 8f3e85512..35bc61c9d 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 30509d3b2..f25a0f5ce 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 11bb01d09..49fde0c9a 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 8acd915f0..304fc35f0 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 766e5ccbb..5996a9080 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, };