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