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