diff options
author | Tim Newsome <tim@sifive.com> | 2017-02-07 11:27:48 -0800 |
---|---|---|
committer | Tim Newsome <tim@sifive.com> | 2017-02-07 11:27:48 -0800 |
commit | 94277648d5a0bb0e8283bbb33e25f6faab11c0d6 (patch) | |
tree | 880c0551627766238f419b4d8126e87e383f5cde /riscv/jtag_dtm.cc | |
parent | 1f65ba49ea665ceed2774a1a62ac32076e4d3025 (diff) | |
download | spike-94277648d5a0bb0e8283bbb33e25f6faab11c0d6.zip spike-94277648d5a0bb0e8283bbb33e25f6faab11c0d6.tar.gz spike-94277648d5a0bb0e8283bbb33e25f6faab11c0d6.tar.bz2 |
OpenOCD does a dmi read and gets dummy value back.
Diffstat (limited to 'riscv/jtag_dtm.cc')
-rw-r--r-- | riscv/jtag_dtm.cc | 100 |
1 files changed, 93 insertions, 7 deletions
diff --git a/riscv/jtag_dtm.cc b/riscv/jtag_dtm.cc index c099e33..5fcc303 100644 --- a/riscv/jtag_dtm.cc +++ b/riscv/jtag_dtm.cc @@ -1,6 +1,8 @@ #include <stdio.h> +#include "decode.h" #include "jtag_dtm.h" +#include "debug_module.h" #if 1 # define D(x) x @@ -8,7 +10,64 @@ # define D(x) #endif +enum { + IR_IDCODE=1, + IR_DTMCONTROL=0x10, + IR_DBUS=0x11 +}; + +#define DTMCONTROL_VERSION 0xf +#define DTMCONTROL_ABITS (0x3f << 4) +#define DTMCONTROL_DBUSSTAT (3<<10) +#define DTMCONTROL_IDLE (7<<12) +#define DTMCONTROL_DBUSRESET (1<<16) + +#define DBUS_OP 3 +#define DBUS_DATA (0xffffffffL<<2) +#define DBUS_ADDRESS ((1L<<(abits+34)) - (1L<<34)) + +#define DBUS_OP_STATUS_SUCCESS 0 +#define DBUS_OP_STATUS_RESERVED 1 +#define DBUS_OP_STATUS_FAILED 2 +#define DBUS_OP_STATUS_BUSY 3 + +#define DBUS_OP_NOP 0 +#define DBUS_OP_READ 1 +#define DBUS_OP_READ_WRITE 2 +#define DBUS_OP_RESERVED 3 + +jtag_dtm_t::jtag_dtm_t(debug_module_t *dm) : + dm(dm), + dtmcontrol((abits << 4) | 1), + dbus(0), + state(TEST_LOGIC_RESET) +{ +} + +void jtag_dtm_t::reset() { + state = TEST_LOGIC_RESET; +} + void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) { + const jtag_state_t next[16][2] = { + /* TEST_LOGIC_RESET */ { RUN_TEST_IDLE, TEST_LOGIC_RESET }, + /* RUN_TEST_IDLE */ { RUN_TEST_IDLE, SELECT_DR_SCAN }, + /* SELECT_DR_SCAN */ { CAPTURE_DR, SELECT_IR_SCAN }, + /* CAPTURE_DR */ { SHIFT_DR, EXIT1_DR }, + /* SHIFT_DR */ { SHIFT_DR, EXIT1_DR }, + /* EXIT1_DR */ { PAUSE_DR, UPDATE_DR }, + /* PAUSE_DR */ { PAUSE_DR, EXIT2_DR }, + /* EXIT2_DR */ { SHIFT_DR, UPDATE_DR }, + /* UPDATE_DR */ { RUN_TEST_IDLE, SELECT_DR_SCAN }, + /* SELECT_IR_SCAN */ { CAPTURE_IR, TEST_LOGIC_RESET }, + /* CAPTURE_IR */ { SHIFT_IR, EXIT1_IR }, + /* SHIFT_IR */ { SHIFT_IR, EXIT1_IR }, + /* EXIT1_IR */ { PAUSE_IR, UPDATE_IR }, + /* PAUSE_IR */ { PAUSE_IR, EXIT2_IR }, + /* EXIT2_IR */ { SHIFT_IR, UPDATE_IR }, + /* UPDATE_IR */ { RUN_TEST_IDLE, SELECT_DR_SCAN } + }; + if (!_tck && tck) { // Positive clock edge. @@ -27,7 +86,7 @@ void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) { state = next[state][_tms]; switch (state) { case TEST_LOGIC_RESET: - ir = idcode_ir; + ir = IR_IDCODE; break; case CAPTURE_DR: capture_dr(); @@ -50,24 +109,29 @@ void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) { } } + D(fprintf(stderr, "state=%2d, tdi=%d, tdo=%d, tms=%d, tck=%d, ir=0x%02x, dr=0x%lx\n", + state, _tdi, _tdo, _tms, _tck, ir, dr)); + _tck = tck; _tms = tms; _tdi = tdi; - - D(fprintf(stderr, "state=%2d tck=%d tms=%d tdi=%d tdo=%d ir=0x%x dr=0x%lx\n", - state, _tck, _tms, _tdi, _tdo, ir, dr)); } void jtag_dtm_t::capture_dr() { switch (ir) { - case idcode_ir: - dr = 0xdeadbeef; + case IR_IDCODE: + dr = idcode; dr_length = 32; break; - case dtmcontrol_ir: + case IR_DTMCONTROL: dr = dtmcontrol; dr_length = 32; + break; + case IR_DBUS: + dr = dbus; + dr_length = abits + 34; + break; default: D(fprintf(stderr, "Unsupported IR: 0x%x\n", ir)); break; @@ -78,4 +142,26 @@ void jtag_dtm_t::capture_dr() void jtag_dtm_t::update_dr() { + D(fprintf(stderr, "Update DR; IR=0x%x, DR=0x%lx (%d bits)\n", + ir, dr, dr_length)); + switch (ir) { + case IR_DBUS: + { + unsigned op = get_field(dr, DBUS_OP); + uint32_t data = get_field(dr, DBUS_DATA); + unsigned address = get_field(dr, DBUS_ADDRESS); + + dbus = dr; + + if (op == DBUS_OP_READ || op == DBUS_OP_READ_WRITE) { + dbus = set_field(dbus, DBUS_DATA, dm->dmi_read(address)); + } + if (op == DBUS_OP_READ_WRITE) { + dm->dmi_write(address, data); + } + + dbus = set_field(dbus, DBUS_OP, DBUS_OP_STATUS_SUCCESS); + } + break; + } } |