nds32: support Andes profiling function 85/1585/5
authorHsiangkai Wang <hsiangkai@gmail.com>
Tue, 27 Aug 2013 08:10:16 +0000 (16:10 +0800)
committerSpencer Oliver <spen@spen-soft.co.uk>
Fri, 13 Sep 2013 19:37:23 +0000 (19:37 +0000)
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>
src/jtag/aice/aice_port.h
src/jtag/aice/aice_usb.c
src/target/nds32.c
src/target/nds32.h
src/target/nds32_v3.c

index 8f3e855129d5d90b102b1867e6069ba438d5383e..35bc61c9d966f56b8a2d308e59c0de1762842f43 100644 (file)
@@ -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
index 30509d3b2c03d1d8c6f96204797fe5e75cff56dc..f25a0f5ce999b2a9b5a203b0924491846fb7ec71 100644 (file)
@@ -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,
 };
index 11bb01d09712411e1607f036b4f1074462345496..49fde0c9abb2c7b89172255fc0d0682b39a4f5d6 100644 (file)
@@ -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)
 {
index 8acd915f0c1899b5d0d5d7c04305859f84187d5f..304fc35f002211e68aae52d020fccb70194cd3ee 100644 (file)
@@ -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)
index 766e5ccbb8873002f08710c48f019fe20081b572..5996a908095efb2dac80fb08d2abb8b94f2a521e 100644 (file)
@@ -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,
 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)