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>
This commit is contained in:
parent
6d86ded4db
commit
9288a59aa1
|
@ -218,6 +218,10 @@ struct aice_port_api_s {
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
int (*set_data_endian)(enum aice_target_endian target_data_endian);
|
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
|
#define AICE_PORT_UNKNOWN 0
|
||||||
|
|
|
@ -390,7 +390,7 @@ static uint32_t usb_out_packets_buffer_length;
|
||||||
static uint32_t usb_in_packets_buffer_length;
|
static uint32_t usb_in_packets_buffer_length;
|
||||||
static enum aice_command_mode aice_command_mode;
|
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);
|
uint32_t num_of_words);
|
||||||
|
|
||||||
static int aice_usb_packet_flush(void)
|
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;
|
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 = {
|
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_count_to_check_dbger = aice_usb_set_count_to_check_dbger,
|
||||||
/** */
|
/** */
|
||||||
.set_data_endian = aice_usb_set_data_endian,
|
.set_data_endian = aice_usb_set_data_endian,
|
||||||
|
/** */
|
||||||
|
.profiling = aice_usb_profiling,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2455,6 +2455,25 @@ int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, b
|
||||||
return ERROR_OK;
|
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,
|
int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address,
|
||||||
uint32_t size, const uint8_t *buffer)
|
uint32_t size, const uint8_t *buffer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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_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_reset_halt(struct nds32 *nds32);
|
||||||
extern int nds32_login(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. */
|
/** Convert target handle to generic Andes target state handle. */
|
||||||
static inline struct nds32 *target_to_nds32(struct target *target)
|
static inline struct nds32 *target_to_nds32(struct target *target)
|
||||||
|
|
|
@ -523,4 +523,6 @@ struct target_type nds32_v3_target = {
|
||||||
|
|
||||||
.get_gdb_fileio_info = nds32_get_gdb_fileio_info,
|
.get_gdb_fileio_info = nds32_get_gdb_fileio_info,
|
||||||
.gdb_fileio_end = nds32_gdb_fileio_end,
|
.gdb_fileio_end = nds32_gdb_fileio_end,
|
||||||
|
|
||||||
|
.profiling = nds32_profiling,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue