diff --git a/src/.uviemon_history b/src/.uviemon_history index 8a570aa5cff964caabdf881cf517c408bd873f8d..ae47117fe4299be5d738c7fe9afefece6a898e0a 100644 --- a/src/.uviemon_history +++ b/src/.uviemon_history @@ -76,3 +76,51 @@ quit exit exit exit +mem 0xff9110000 +mem 0xff9110004 +mem 0xff9200000 +mem 0xff9200000 128 +mem 0xff9200000 164 +mem 0xff9200000 64 +mem 0xff9200000 68 +mem 0xff9100000 64 +quit +exit +inst +inst +inst 11 +inst +inst +break leon3_dsu.c:493 +quit +inst +inst +inst +inst +inst +inst +isnt +inst +inst +mem 0xE010ffb0 +mem 0xE010ffb0 128 +inst +isnt +inst +inst +isnt +inst +inst +inst +inst +inst +inst +mem 0xe0110000 +0xe0100000 +mem 0xe0100000 +inst +inst +inst +inst +inst +inst diff --git a/src/leon3_dsu.c b/src/leon3_dsu.c index ff539afdd3b93f8b7df96b3c1f18136926fcaec7..e449064bd70d0cddcd88cf2b6247fbccbf44909c 100644 --- a/src/leon3_dsu.c +++ b/src/leon3_dsu.c @@ -40,6 +40,7 @@ */ #include <stddef.h> // size_t +#include <stdlib.h> // malloc, free #include "leon3_dsu.h" #include "ftdi_device.hpp" @@ -918,3 +919,66 @@ void dsu_set_reg_fp(uint32_t cpu, uint32_t cwp, uint32_t val) if (reg) iowrite32((uint32_t) reg, val); } + + + +/** + * @brief get the last line_count lines from the instruction trace buffer + * + * @param cpu the cpu number + * @param buffer the buffer to write the lines to + * @param line_count the number of lines to read (instructions can be multiple lines) + * @param line_start the number of lines to skip when going backwards + */ +void dsu_get_instr_trace_buffer(uint32_t cpu, struct instr_trace_buffer_line *buffer, uint32_t line_count, uint32_t line_start) +{ + + DWORD *data = (DWORD*) malloc(DSU_INST_TRCE_BUF_LINE_SIZE * line_count); + + uint32_t inst_trce_ctrl_reg = ioread32((uint32_t) DSU_BASE(cpu) + DSU_INST_TRCE_CTRL); + uint32_t inst_pointer = inst_trce_ctrl_reg & 0xFF; + + /* inst_pointer points next line that will be written + * ignore line_start lines + * go back line_count lines to read them + * this can very likely overflow, that is the reason for the modulo operation + */ + uint32_t first_line_to_read = inst_pointer - line_start - line_count; + uint32_t offset_start = (first_line_to_read * DSU_INST_TRCE_BUF_LINE_SIZE) % DSU_INST_TRCE_BUF_SIZE; + uint32_t read_size, line_ptr = 0; + + /* if an overflow in the instruction trace would occur read only until the + * end of the buffer in the first step + */ + if (offset_start + line_count * DSU_INST_TRCE_BUF_LINE_SIZE > DSU_INST_TRCE_BUF_SIZE) + read_size = DSU_INST_TRCE_BUF_SIZE - offset_start; + else + read_size = line_count * DSU_INST_TRCE_BUF_LINE_SIZE; + + /* Read size in dwords */ + ioread32(DSU_BASE(cpu) + DSU_INST_TRCE_BUF_START + offset_start, data, read_size / 4); + + for(uint32_t i = 0; i < read_size / 4; i += 4) { + buffer[line_ptr].field[0] = data[i + 0]; + buffer[line_ptr].field[1] = data[i + 1]; + buffer[line_ptr].field[2] = data[i + 2]; + buffer[line_ptr].field[3] = data[i + 3]; + line_ptr++; + } + + /* Read remaining data in case of an overflow in the circular instruction trace buffer */ + uint32_t remaining_size = line_count * DSU_INST_TRCE_BUF_LINE_SIZE - read_size; + if (remaining_size > 0) { + ioread32(DSU_BASE(cpu) + DSU_INST_TRCE_BUF_START, data, remaining_size / 4); + + for(uint32_t i = 0; i < remaining_size / 4; i += 4) { + buffer[line_ptr].field[0] = data[i + 0]; + buffer[line_ptr].field[1] = data[i + 1]; + buffer[line_ptr].field[2] = data[i + 2]; + buffer[line_ptr].field[3] = data[i + 3]; + line_ptr++; + } + } + + free(data); +} diff --git a/src/leon3_dsu.h b/src/leon3_dsu.h index 8afdd127dbe7d6124d6c600f6c7c6cf0b04a3196..680e8eba2d777ac21ffb4b5b4159a6e9adab94db 100644 --- a/src/leon3_dsu.h +++ b/src/leon3_dsu.h @@ -64,7 +64,9 @@ #define DSU_AHB_MASK_2 0x00005c #define DSU_INST_TRCE_BUF_START 0x100000 +#define DSU_INST_TRCE_BUF_SIZE 0x10000 #define DSU_INST_TRCE_BUF_LINES 256 +#define DSU_INST_TRCE_BUF_LINE_SIZE 16 #define DSU_INST_TRCE_CTRL 0x110000 #define DSU_AHB_TRCE_BUF_START 0x200000 @@ -181,7 +183,10 @@ struct instr_trace_buffer_line { uint32_t multi_cycle_inst :1; uint32_t timetag :30; uint32_t load_store_param :32; - uint32_t program_cntr :30; + /* program_cntr is still a 32bit number, + * but the two lsb are always 0 and thus used for something else + */ + uint32_t program_cntr :30; uint32_t instr_trap :1; uint32_t proc_error_mode :1; uint32_t opcode :32; @@ -259,6 +264,9 @@ uint32_t dsu_get_reg_tbr(uint32_t cpu); uint32_t dsu_get_reg_trap(uint32_t cpu); void dsu_set_reg_psr(uint32_t cpu, uint32_t val); +/* line_start is relative with 0 being the last executed line */ +void dsu_get_instr_trace_buffer(uint32_t cpu, struct instr_trace_buffer_line *buffer, uint32_t line_count, uint32_t line_start); + uint32_t dsu_get_reg_wim(uint32_t cpu); uint32_t dsu_get_reg_pc(uint32_t cpu); uint32_t dsu_get_reg_sp(uint32_t cpu, uint32_t cwp); diff --git a/src/uviemon.cpp b/src/uviemon.cpp index 4680bce3c0b3d2ac8a89c1d1cfdacb5a0c1d0ec5..7ebc905a2a12f47b90742205cc935d2168f78adc 100644 --- a/src/uviemon.cpp +++ b/src/uviemon.cpp @@ -39,10 +39,12 @@ void console() raw_input = readline("uviemon> "); // Read input from the user + if (!raw_input) + break; + if (raw_input && *raw_input) add_history(raw_input); - parse_result = parse_input(raw_input); free(raw_input); } diff --git a/src/uviemon_cli.cpp b/src/uviemon_cli.cpp index a7acf79a6781618d06438bdf3a3044b9c464a131..8594fa5c3bd8181b822f0bfeff89b933c4e6886c 100644 --- a/src/uviemon_cli.cpp +++ b/src/uviemon_cli.cpp @@ -18,12 +18,16 @@ #include <fstream> // For loading a file in load() #include <cmath> // For std::ceil in load() +#include <stdlib.h> + +#include "leon3_dsu.h" + using namespace std; //static int command_count; -#define COMMAND_COUNT 13 +#define COMMAND_COUNT 14 static command commands[COMMAND_COUNT] = { { "help", &help }, @@ -40,6 +44,8 @@ static command commands[COMMAND_COUNT] = { { "bdump", &bdump }, + { "inst", &inst }, + { "load", &load }, { "verify", &verify }, { "run", &run } @@ -49,6 +55,8 @@ static command commands[COMMAND_COUNT] = { //static void register_command(command com, const char *name, void (*function)(const char*, int, char [MAX_PARAMETERS][MAX_PARAM_LENGTH])); static DWORD parse_parameter(char *param); +static void parse_opcode(char *buffer, uint32_t opcode, uint32_t address); + std::unordered_map<int, std::string> tt_errors = { {0x0, "[reset]: Power-on reset"}, {0x2b, "[write_error]: write buffer error"}, @@ -249,7 +257,9 @@ void help(const char *command, int param_count, char params[MAX_PARAMETERS][MAX_ printf(" wmemh: \t Write <data#2> 16-bit WORD to a memory <address#1>\n"); printf(" wmemb: \t Write <data#2> 8-bit BYTE to a memory <address#1>\n\n"); - printf(" bdump: \t Read <length#2> BYTEs of data from memory starting at an <address#1>, saving the data to a <filePath#1>\n\n"); + printf(" bdump:\t Read <length#2> BYTEs of data from memory starting at an <address#1>, saving the data to a <filePath#1>\n\n"); + + printf(" isnt:\t Prints the last <instruction_cnt#1> instruction to stdout\n\n"); printf(" load: \t Write a file with <filePath#1> to the device memory\n"); printf(" verify: \t Verify a file written to the device memory with <filePath#1>\n"); @@ -437,6 +447,118 @@ void wmemx(const char *command, int param_count, char params[MAX_PARAMETERS][MAX } } +void inst(const char* command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]) +{ + uint32_t instr_count = 11; + + if (param_count > 1) { + printf("Inst only needs 1 parameter: the number of lines"); + return; + } + + if (param_count == 1) { + if ( (instr_count = strtol(params[0], NULL, 10)) == 0) { + printf("Parameter 1 must be a positive integer"); + return; + } + } + + + struct instr_trace_buffer_line *buffer = (instr_trace_buffer_line*) malloc(sizeof(instr_trace_buffer_line) * instr_count * 2); + + /* TODO: manage active cpu */ + dsu_get_instr_trace_buffer(0, buffer, instr_count * 2, 0); + + + uint32_t i_cntr = 0; + int i, page = 0; + + /* go back instr_count number of instructions counting multi line instructions */ + /* there must be a better way to do this */ + while(i_cntr < instr_count) { + for(i = instr_count * 2; i > -1; i--) { + /* count all non multi-line instruction as unique instructions */ + if ((buffer[i].field[0] & 0x40000000) == 0) + i_cntr++; + + if (i_cntr == instr_count) + break; + } + + if (i_cntr < instr_count) { + page++; + dsu_get_instr_trace_buffer(0, buffer, instr_count * 2, page * instr_count * 2); + } + } + + uint32_t first_line = i; + char operation[31]; + + /* print header */ + printf(" %9s %8s %30s %10s %10s\n", "TIME ", "ADDRESS ", "INSTRUCTION ", "RESULT ", "SYMBOL"); + while(page > -1) { + for(uint32_t j = first_line; j < instr_count * 2; j++) { + /* Check for non multi-line instruction second bit is zero */ + if ((buffer[j].field[0] & 0x40000000) == 0) { + if (j != first_line) { + printf("] -\n"); + } + + /* first is the time tag with first 2 bits set to zero + * second is program counter with last two bits set to zero + */ + parse_opcode(operation, buffer[j].field[3], buffer[j].field[2] & 0xFFFFFFFC); + printf(" %9u %08x %-30s [", + buffer[j].field[0] & 0x3FFFFFFF, + buffer[j].field[2] & 0xFFFFFFFC, + operation); + + + /* Check for instruction trap bit 2 is set */ + if ((buffer[j].field[2] & 0x2) == 0x2) + printf(" TRAP "); + else + printf("%08x", buffer[j].load_store_param); + + } else { + printf(" %08x", buffer[j].load_store_param); + } + } + + if (--page < 0) + break; + + dsu_get_instr_trace_buffer(0, buffer, instr_count * 2, page * instr_count * 2); + } + + printf("] -\n"); + + + free(buffer); +} + + +static void parse_opcode(char *buffer, uint32_t opcode, uint32_t address) +{ + struct opcode op; + op.opcode_raw = opcode; + + switch (op.op_call.op) { + case 0: + sprintf(buffer, "%#08x", opcode); + break; + case 1: + sprintf(buffer, "call %#08x", address + 4 * op.op_call.disp30); + break; + case 2: + sprintf(buffer, "%#08x", opcode); + break; + case 3: + sprintf(buffer, "%#08x", opcode); + break; + } +} + void wmem(DWORD addr, DWORD data) { printf("Writing to memory... "); diff --git a/src/uviemon_cli.hpp b/src/uviemon_cli.hpp index 99e935a587b23db3596ef71cecafc54f3fbd0083..0e9931dbce65913dd006a5eacb99f7d156b1a18e 100644 --- a/src/uviemon_cli.hpp +++ b/src/uviemon_cli.hpp @@ -20,6 +20,7 @@ #include <stdio.h> #include <stdbool.h> #include <string.h> +#include <stdint.h> #define MAX_PARAMETERS 3 #define MAX_PARAM_LENGTH 50 @@ -44,6 +45,61 @@ int parse_input(char *input); void print_help_text(); //void cleanup(); +struct op_call_t { + uint32_t disp30 :30; + uint32_t op :2; +}; +struct op_sethi_t { + uint32_t imm22 :22; + uint32_t op2 :3; + uint32_t rd :5; + uint32_t op :2; +}; +struct op_branch_t { + uint32_t disp22 :22; + uint32_t op2 :3; + uint32_t cond :4; + uint32_t a :1; + uint32_t op :2; +}; +struct op_other_1_t { + uint32_t rs2 :5; + uint32_t asi :8; + uint32_t i :1; + uint32_t rs1 :5; + uint32_t op3 :6; + uint32_t rd :5; + uint32_t op :2; +}; +struct op_other_2_t { + uint32_t simm13 :13; + uint32_t i :1; + uint32_t rs1 :5; + uint32_t op3 :6; + uint32_t rd :5; + uint32_t op :2; +}; +struct op_other_3_t { + uint32_t rs2 :5; + uint32_t opf :9; + uint32_t rs1 :5; + uint32_t op3 :6; + uint32_t rd :5; + uint32_t op :2; +}; + + +struct opcode { + union { + struct op_call_t op_call; + struct op_sethi_t op_sethi; + struct op_branch_t op_branch; + struct op_other_1_t op_other_1; + struct op_other_2_t op_other_2; + struct op_other_3_t op_other_3; + uint32_t opcode_raw; + }; +}__attribute__((packed)); /* Command functions */ void help (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]); @@ -56,6 +112,7 @@ void load (const char *command, int param_count, char params[MAX_PARAMETERS][MA void verify(const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]); void bdump (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]); void wash (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]); +void inst (const char *command, int param_count, char params[MAX_PARAMETERS][MAX_PARAM_LENGTH]); void wmem(DWORD addr, DWORD data); void wmemh(DWORD addr, WORD data);