From 1b349df6388f0bdf95be129ee0aac49ff241792e Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 6 Jun 2016 14:07:54 -0700 Subject: [PATCH] WIP hackery. Main thing I added is code to output "verilog" for every JTAG op we do, so we can run the same thing in simulation. --- src/jtag/core.c | 106 ++++++++++++++++++- src/target/riscv/opcodes.h | 43 +++++--- src/target/riscv/riscv.c | 210 ++++++++++++++++++++++++++++++++++++- 3 files changed, 336 insertions(+), 23 deletions(-) diff --git a/src/jtag/core.c b/src/jtag/core.c index ed5d47abf..70ac3aa40 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -836,7 +836,111 @@ int default_interface_jtag_execute_queue(void) return ERROR_FAIL; } - return jtag->execute_queue(); + int result = jtag->execute_queue(); + + struct jtag_command *cmd = jtag_command_queue; + while (debug_level >= LOG_LVL_DEBUG && cmd) { + switch (cmd->type) { + case JTAG_SCAN: + LOG_DEBUG("JTAG %s SCAN to %s", + cmd->cmd.scan->ir_scan ? "IR" : "DR", + tap_state_name(cmd->cmd.scan->end_state)); + for (int i = 0; i < cmd->cmd.scan->num_fields; i++) { + struct scan_field *field = cmd->cmd.scan->fields + i; + if (field->out_value) { + char *str = buf_to_str(field->out_value, field->num_bits, 16); + LOG_DEBUG(" %db out: %s", field->num_bits, str); + free(str); + } + if (field->in_value) { + char *str = buf_to_str(field->in_value, field->num_bits, 16); + LOG_DEBUG(" %db in: %s", field->num_bits, str); + free(str); + } + if (field->check_value) { + char *str = buf_to_str(field->check_value, field->num_bits, 16); + LOG_DEBUG(" %db check: %s", field->num_bits, str); + free(str); + } + if (field->check_mask) { + char *str = buf_to_str(field->check_mask, field->num_bits, 16); + LOG_DEBUG(" %db mask: %s", field->num_bits, str); + free(str); + } + } + uint8_t *buf = NULL; + int scan_bits = jtag_build_buffer(cmd->cmd.scan, &buf); + char *str_out = buf_to_str(buf, scan_bits, 16); + free(buf); + LOG_DEBUG("vvv jtag_scan(%d, %d, %d'h%s, %d); // %s", + cmd->cmd.scan->ir_scan, + scan_bits, + scan_bits, str_out, + cmd->cmd.scan->end_state, tap_state_name(cmd->cmd.scan->end_state)); + free(str_out); + + struct scan_field *last_field = cmd->cmd.scan->fields + cmd->cmd.scan->num_fields - 1; + if (last_field->in_value) { + char *str_in = buf_to_str(last_field->in_value, last_field->num_bits, 16); + LOG_DEBUG("vvv jtag_check_tdo(%d, %d'h%s);", + last_field->num_bits, + last_field->num_bits, str_in); + free(str_in); + } + break; + case JTAG_TLR_RESET: + LOG_DEBUG("JTAG TLR RESET to %s", + tap_state_name(cmd->cmd.statemove->end_state)); + LOG_DEBUG("vvv jtag_tlr_reset(%d); // %s", + cmd->cmd.statemove->end_state, + tap_state_name(cmd->cmd.statemove->end_state)); + break; + case JTAG_RUNTEST: + LOG_DEBUG("JTAG RUNTEST %d cycles to %s", + cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + LOG_DEBUG("vvv jtag_runtest(%d, %d); // %s", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state, + tap_state_name(cmd->cmd.runtest->end_state)); + break; + case JTAG_RESET: + { + const char *reset_str[3] = { + "leave", "deassert", "assert" + }; + LOG_DEBUG("JTAG RESET %s TRST, %s SRST", + reset_str[cmd->cmd.reset->trst + 1], + reset_str[cmd->cmd.reset->srst + 1]); + LOG_DEBUG("vvv jtag_reset(%d, %d);", + cmd->cmd.reset->trst, cmd->cmd.reset->srst); + } + break; + case JTAG_PATHMOVE: + LOG_DEBUG("JTAG PATHMOVE (TODO)"); + abort(); + break; + case JTAG_SLEEP: + LOG_DEBUG("JTAG SLEEP (TODO)"); + abort(); + break; + case JTAG_STABLECLOCKS: + LOG_DEBUG("JTAG STABLECLOCKS (TODO)"); + abort(); + break; + case JTAG_TMS: + LOG_DEBUG("JTAG STABLECLOCKS (TODO)"); + abort(); + break; + default: + LOG_ERROR("Unknown JTAG command: %d", cmd->type); + abort(); + break; + } + cmd = cmd->next; + } + + return result; } void jtag_execute_queue_noclear(void) diff --git a/src/target/riscv/opcodes.h b/src/target/riscv/opcodes.h index 1e46b80f4..e10d6cbb6 100644 --- a/src/target/riscv/opcodes.h +++ b/src/target/riscv/opcodes.h @@ -79,22 +79,6 @@ static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) MATCH_LB; } -static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) -{ - return (bits(imm, 11, 0) << 20) | - (src << 15) | - (dest << 7) | - MATCH_XORI; -} - -static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) -{ - return (bits(shamt, 4, 0) << 20) | - (src << 15) | - (dest << 7) | - MATCH_SRLI; -} - static uint32_t csrci(unsigned int csr, uint16_t imm) { return (csr << 20) | (bits(imm, 4, 0) << 15) | @@ -126,7 +110,15 @@ static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) MATCH_FSW; } -/* +static uint32_t flw(unsigned int src, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 5) << 25) | + (bits(src, 4, 0) << 20) | + (base << 15) | + (bits(offset, 4, 0) << 7) | + MATCH_FLW; +} + static uint32_t li(unsigned int dest, uint16_t imm) { return addi(dest, 0, imm); @@ -139,6 +131,7 @@ static uint32_t lui(unsigned int dest, uint32_t imm) MATCH_LUI; } +/* static uint32_t fence_i(void) { return MATCH_FENCE_I; @@ -186,8 +179,24 @@ static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) (dest << 7) | MATCH_ORI; } + +static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) +{ + return (bits(imm, 11, 0) << 20) | + (src << 15) | + (dest << 7) | + MATCH_XORI; +} */ +static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) +{ + return (bits(shamt, 4, 0) << 20) | + (src << 15) | + (dest << 7) | + MATCH_SRLI; +} + static uint32_t nop(void) { return addi(0, 0, 0); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 769c5ca2e..258bf72f5 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -268,17 +268,21 @@ static uint32_t dram_read32(struct target *target, unsigned int index) static void dram_write32(struct target *target, unsigned int index, uint32_t value, bool set_interrupt) { + riscv_info_t *info = (riscv_info_t *) target->arch_info; // TODO: check cache to see if this even needs doing. uint64_t dbus_value = DMCONTROL_HALTNOT | value; if (set_interrupt) dbus_value |= DMCONTROL_INTERRUPT; dbus_write(target, dram_address(index), dbus_value); + info->dram_valid |= (1<dram_valid) { + // Cycle through addresses, so we have more debug info. Only look at + // ones that we've written, to reduce data mismatch between real life + // and simulation. + do { + next_address = (next_address + 1) % 64; + } while (!(info->dram_valid & (1<arch_info; + // TODO: S0 and S1 if (reg->number <= REG_XPR31) { dram_write32(target, 0, sw(reg->number - REG_XPR0, ZERO, DEBUG_RAM_START), false); dram_write_jump(target, 1, true); @@ -449,7 +461,40 @@ static int register_get(struct reg *reg) static int register_set(struct reg *reg, uint8_t *buf) { - return ERROR_FAIL; + struct target *target = (struct target *) reg->arch_info; + + uint32_t value = buf_get_u32(buf, 0, 32); + + LOG_DEBUG("write 0x%x to %s", value, reg->name); + + // TODO: S0 and S1 + if (reg->number <= REG_XPR31) { + dram_write32(target, 0, lw(reg->number - REG_XPR0, ZERO, DEBUG_RAM_START + 16), false); + dram_write_jump(target, 1, false); + } else if (reg->number == REG_PC) { + dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); + dram_write32(target, 1, csrw(S0, CSR_DPC), false); + dram_write_jump(target, 2, false); + } else if (reg->number >= REG_FPR0 && reg->number <= REG_FPR31) { + dram_write32(target, 0, flw(reg->number - REG_FPR0, 0, DEBUG_RAM_START + 16), false); + dram_write_jump(target, 1, false); + } else if (reg->number >= REG_CSR0 && reg->number <= REG_CSR4095) { + dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); + dram_write32(target, 1, csrw(S0, reg->number - REG_CSR0), false); + dram_write_jump(target, 2, false); + } else { + LOG_ERROR("Don't know how to read register %d (%s)", reg->number, reg->name); + return ERROR_FAIL; + } + + dram_write32(target, 4, value, true); + + if (wait_for_debugint_clear(target) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + return ERROR_FAIL; + } + + return ERROR_OK; } static struct reg_arch_type riscv_reg_arch_type = { @@ -504,6 +549,8 @@ static int riscv_init_target(struct command_context *cmd_ctx, } update_reg_list(target); + info->dram_valid = 0; + return ERROR_OK; } @@ -649,7 +696,6 @@ static int riscv_examine(struct target *target) info->dram = malloc(info->dramsize * 4); if (!info->dram) return ERROR_FAIL; - info->dram_valid = 0; if (get_field(dminfo, DMINFO_AUTHTYPE) != 0) { LOG_ERROR("Authentication required by RISC-V core but not " @@ -657,6 +703,7 @@ static int riscv_examine(struct target *target) return ERROR_FAIL; } +#if 0 // Figure out XLEN. dram_write32(target, 0, xori(S1, ZERO, -1), false); // 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff @@ -691,7 +738,62 @@ static int riscv_examine(struct target *target) LOG_ERROR("Debug interrupt didn't clear."); return ERROR_FAIL; } +#else +#if 1 + // Blue blue red + dram_write32(target, 1, nop(), false); + dram_write32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4), false); + dram_write_jump(target, 0, true); + if (wait_for_debugint_clear(target) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + return ERROR_FAIL; + } +#endif + +#if 0 + // no effect + dram_write32(target, 1, ~nop(), false); + dram_write32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4), false); + dram_write_jump(target, 0, true); + if (wait_for_debugint_clear(target) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + return ERROR_FAIL; + } +#endif + + srli(0,0,0);nop(); // TODO + +#if 0 + // Blue blue red red + dram_write32(target, 0, nop(), false); + dram_write32(target, 1, nop(), false); + dram_write32(target, 2, sw(S1, ZERO, DEBUG_RAM_START), false); + dram_write32(target, 3, srli(S1, S1, 31), false); + dram_write32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4), false); + dram_write_jump(target, 5, true); + if (wait_for_debugint_clear(target) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + return ERROR_FAIL; + } +#endif + +#if 0 + // Blue off red red + dram_write32(target, 0, nop(), false); + dram_write32(target, 1, sw(S1, ZERO, DEBUG_RAM_START), false); + dram_write32(target, 2, srli(S1, S1, 31), false); + dram_write32(target, 3, sw(S1, ZERO, DEBUG_RAM_START + 4), false); + dram_write_jump(target, 4, true); + if (wait_for_debugint_clear(target) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + return ERROR_FAIL; + } +#endif + +#endif + +#if 0 uint32_t word0 = dram_read32(target, 0); uint32_t word1 = dram_read32(target, 1); if (word0 == 1 && word1 == 0) { @@ -706,10 +808,38 @@ static int riscv_examine(struct target *target) return ERROR_FAIL; } LOG_DEBUG("Discovered XLEN is %d", info->xlen); +#else + info->xlen = 32; +#endif // Update register list to match discovered XLEN. update_reg_list(target); + // TODO + // smoke test + //dram_write32(target, 4, 0x700020a0, false); + //dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); + //dram_write32(target, 1, sw(ZERO, S0, 0), false); + //dram_write32(target, 2, jal(ZERO, 0), true); + //dram_write_jump(target, 2, true); + + li(0,0); // TODO: remove + + dram_write32(target, 0, lui(S0, 0x70002), false); + dram_write32(target, 1, lui(S1, 0xccccc), false); + dram_write32(target, 2, sw(S1, S0, 0xa0), false); + dram_write32(target, 3, jal(ZERO, 0), true); + // 400: 70002437 lui s0,0x70002 + // 404: 0a000493 li s1,160 + // 408: 0a942023 sw s1,160(s0) # 700020a0 + // 40c: 0000006f j 40c + + if (wait_for_debugint_clear(target) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + return ERROR_FAIL; + } + dram_read32(target, 4); + target_set_examined(target); return ERROR_OK; @@ -722,12 +852,16 @@ static int riscv_poll(struct target *target) if (bits.haltnot && bits.interrupt) { target->state = TARGET_DEBUG_RUNNING; + LOG_DEBUG("debug running"); } else if (bits.haltnot && !bits.interrupt) { target->state = TARGET_HALTED; + LOG_DEBUG("halted"); } else if (!bits.haltnot && bits.interrupt) { // Target is halting. There is no state for that, so don't change anything. + LOG_DEBUG("halting"); } else if (!bits.haltnot && !bits.interrupt) { target->state = TARGET_RUNNING; + LOG_DEBUG("running"); } return ERROR_OK; @@ -866,6 +1000,7 @@ static int riscv_read_memory(struct target *target, uint32_t address, return ERROR_OK; } +#if 0 static int riscv_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { @@ -942,6 +1077,71 @@ static int riscv_write_memory(struct target *target, uint32_t address, return ERROR_OK; } +#else +/** Inefficient implementation that doesn't require conditional writes. */ +static int riscv_write_memory(struct target *target, uint32_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + // TODO: save/restore T0 + + // Set up the address. + + // Write program. + dram_write32(target, 0, lw(S1, ZERO, DEBUG_RAM_START + 16), false); + switch (size) { + case 1: + dram_write32(target, 1, lb(S0, ZERO, DEBUG_RAM_START + 20), false); + dram_write32(target, 2, sb(S0, S1, 0), false); + break; + case 2: + dram_write32(target, 1, lh(S0, ZERO, DEBUG_RAM_START + 20), false); + dram_write32(target, 2, sh(S0, S1, 0), false); + break; + case 4: + dram_write32(target, 1, lw(S0, ZERO, DEBUG_RAM_START + 20), false); + dram_write32(target, 2, sw(S0, S1, 0), false); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + return ERROR_FAIL; + } + dram_write_jump(target, 3, false); + + for (uint32_t i = 0; i < count; i++) { + // Write the next value and set interrupt. + uint32_t value; + uint32_t offset = size * i; + switch (size) { + case 1: + value = buffer[offset]; + break; + case 2: + value = buffer[offset] | + (buffer[offset+1] << 8); + break; + case 4: + value = buffer[offset] | + ((uint32_t) buffer[offset+1] << 8) | + ((uint32_t) buffer[offset+2] << 16) | + ((uint32_t) buffer[offset+3] << 24); + break; + default: + return ERROR_FAIL; + } + + dram_write32(target, 4, address + offset, false); + dram_write32(target, 5, value, true); + + if (wait_for_debugint_clear(target) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} +#endif static int riscv_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size,