aboutsummaryrefslogtreecommitdiff
path: root/riscv/jtag_dtm.cc
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2017-02-07 11:27:48 -0800
committerTim Newsome <tim@sifive.com>2017-02-07 11:27:48 -0800
commit94277648d5a0bb0e8283bbb33e25f6faab11c0d6 (patch)
tree880c0551627766238f419b4d8126e87e383f5cde /riscv/jtag_dtm.cc
parent1f65ba49ea665ceed2774a1a62ac32076e4d3025 (diff)
downloadspike-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.cc100
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;
+ }
}