OpenOCD does a dmi read and gets dummy value back.
[riscv-isa-sim.git] / riscv / jtag_dtm.cc
1 #include <stdio.h>
2
3 #include "decode.h"
4 #include "jtag_dtm.h"
5 #include "debug_module.h"
6
7 #if 1
8 # define D(x) x
9 #else
10 # define D(x)
11 #endif
12
13 enum {
14 IR_IDCODE=1,
15 IR_DTMCONTROL=0x10,
16 IR_DBUS=0x11
17 };
18
19 #define DTMCONTROL_VERSION 0xf
20 #define DTMCONTROL_ABITS (0x3f << 4)
21 #define DTMCONTROL_DBUSSTAT (3<<10)
22 #define DTMCONTROL_IDLE (7<<12)
23 #define DTMCONTROL_DBUSRESET (1<<16)
24
25 #define DBUS_OP 3
26 #define DBUS_DATA (0xffffffffL<<2)
27 #define DBUS_ADDRESS ((1L<<(abits+34)) - (1L<<34))
28
29 #define DBUS_OP_STATUS_SUCCESS 0
30 #define DBUS_OP_STATUS_RESERVED 1
31 #define DBUS_OP_STATUS_FAILED 2
32 #define DBUS_OP_STATUS_BUSY 3
33
34 #define DBUS_OP_NOP 0
35 #define DBUS_OP_READ 1
36 #define DBUS_OP_READ_WRITE 2
37 #define DBUS_OP_RESERVED 3
38
39 jtag_dtm_t::jtag_dtm_t(debug_module_t *dm) :
40 dm(dm),
41 dtmcontrol((abits << 4) | 1),
42 dbus(0),
43 state(TEST_LOGIC_RESET)
44 {
45 }
46
47 void jtag_dtm_t::reset() {
48 state = TEST_LOGIC_RESET;
49 }
50
51 void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) {
52 const jtag_state_t next[16][2] = {
53 /* TEST_LOGIC_RESET */ { RUN_TEST_IDLE, TEST_LOGIC_RESET },
54 /* RUN_TEST_IDLE */ { RUN_TEST_IDLE, SELECT_DR_SCAN },
55 /* SELECT_DR_SCAN */ { CAPTURE_DR, SELECT_IR_SCAN },
56 /* CAPTURE_DR */ { SHIFT_DR, EXIT1_DR },
57 /* SHIFT_DR */ { SHIFT_DR, EXIT1_DR },
58 /* EXIT1_DR */ { PAUSE_DR, UPDATE_DR },
59 /* PAUSE_DR */ { PAUSE_DR, EXIT2_DR },
60 /* EXIT2_DR */ { SHIFT_DR, UPDATE_DR },
61 /* UPDATE_DR */ { RUN_TEST_IDLE, SELECT_DR_SCAN },
62 /* SELECT_IR_SCAN */ { CAPTURE_IR, TEST_LOGIC_RESET },
63 /* CAPTURE_IR */ { SHIFT_IR, EXIT1_IR },
64 /* SHIFT_IR */ { SHIFT_IR, EXIT1_IR },
65 /* EXIT1_IR */ { PAUSE_IR, UPDATE_IR },
66 /* PAUSE_IR */ { PAUSE_IR, EXIT2_IR },
67 /* EXIT2_IR */ { SHIFT_IR, UPDATE_IR },
68 /* UPDATE_IR */ { RUN_TEST_IDLE, SELECT_DR_SCAN }
69 };
70
71 if (!_tck && tck) {
72 // Positive clock edge.
73
74 switch (state) {
75 case SHIFT_DR:
76 dr >>= 1;
77 dr |= (uint64_t) _tdi << (dr_length-1);
78 break;
79 case SHIFT_IR:
80 ir >>= 1;
81 ir |= _tdi << (ir_length-1);
82 break;
83 default:
84 break;
85 }
86 state = next[state][_tms];
87 switch (state) {
88 case TEST_LOGIC_RESET:
89 ir = IR_IDCODE;
90 break;
91 case CAPTURE_DR:
92 capture_dr();
93 break;
94 case SHIFT_DR:
95 _tdo = dr & 1;
96 break;
97 case UPDATE_DR:
98 update_dr();
99 break;
100 case CAPTURE_IR:
101 break;
102 case SHIFT_IR:
103 _tdo = ir & 1;
104 break;
105 case UPDATE_IR:
106 break;
107 default:
108 break;
109 }
110 }
111
112 D(fprintf(stderr, "state=%2d, tdi=%d, tdo=%d, tms=%d, tck=%d, ir=0x%02x, dr=0x%lx\n",
113 state, _tdi, _tdo, _tms, _tck, ir, dr));
114
115 _tck = tck;
116 _tms = tms;
117 _tdi = tdi;
118 }
119
120 void jtag_dtm_t::capture_dr()
121 {
122 switch (ir) {
123 case IR_IDCODE:
124 dr = idcode;
125 dr_length = 32;
126 break;
127 case IR_DTMCONTROL:
128 dr = dtmcontrol;
129 dr_length = 32;
130 break;
131 case IR_DBUS:
132 dr = dbus;
133 dr_length = abits + 34;
134 break;
135 default:
136 D(fprintf(stderr, "Unsupported IR: 0x%x\n", ir));
137 break;
138 }
139 D(fprintf(stderr, "Capture DR; IR=0x%x, DR=0x%lx (%d bits)\n",
140 ir, dr, dr_length));
141 }
142
143 void jtag_dtm_t::update_dr()
144 {
145 D(fprintf(stderr, "Update DR; IR=0x%x, DR=0x%lx (%d bits)\n",
146 ir, dr, dr_length));
147 switch (ir) {
148 case IR_DBUS:
149 {
150 unsigned op = get_field(dr, DBUS_OP);
151 uint32_t data = get_field(dr, DBUS_DATA);
152 unsigned address = get_field(dr, DBUS_ADDRESS);
153
154 dbus = dr;
155
156 if (op == DBUS_OP_READ || op == DBUS_OP_READ_WRITE) {
157 dbus = set_field(dbus, DBUS_DATA, dm->dmi_read(address));
158 }
159 if (op == DBUS_OP_READ_WRITE) {
160 dm->dmi_write(address, data);
161 }
162
163 dbus = set_field(dbus, DBUS_OP, DBUS_OP_STATUS_SUCCESS);
164 }
165 break;
166 }
167 }