Pavel Chromy style fixes.
[fw/openocd] / src / jtag / bitq.c
1 /***************************************************************************\r
2  *   Copyright (C) 2007 by Pavel Chromy                                    *\r
3  *   chromy@asix.cz                                                        *\r
4  *                                                                         *\r
5  *   This program is free software; you can redistribute it and/or modify  *\r
6  *   it under the terms of the GNU General Public License as published by  *\r
7  *   the Free Software Foundation; either version 2 of the License, or     *\r
8  *   (at your option) any later version.                                   *\r
9  *                                                                         *\r
10  *   This program is distributed in the hope that it will be useful,       *\r
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
13  *   GNU General Public License for more details.                          *\r
14  *                                                                         *\r
15  *   You should have received a copy of the GNU General Public License     *\r
16  *   along with this program; if not, write to the                         *\r
17  *   Free Software Foundation, Inc.,                                       *\r
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
19  ***************************************************************************/\r
20 #ifdef HAVE_CONFIG_H\r
21 #include "config.h"\r
22 #endif\r
23 \r
24 #include "bitq.h"\r
25 \r
26 /* project specific includes */\r
27 #include "log.h"\r
28 #include "types.h"\r
29 #include "jtag.h"\r
30 #include "configuration.h"\r
31 \r
32 /* system includes */\r
33 #include <string.h>\r
34 #include <stdlib.h>\r
35 #include <unistd.h>\r
36 \r
37 #include <sys/time.h>\r
38 #include <time.h>\r
39 \r
40 \r
41 bitq_interface_t *bitq_interface; /* low level bit queue interface */\r
42 \r
43 bitq_state_t bitq_in_state; /* state of input queue */\r
44 \r
45 u8 *bitq_in_buffer; /* buffer dynamically reallocated as needed */\r
46 unsigned long bitq_in_bufsize=32; /* min. buffer size */\r
47 \r
48 \r
49 /*\r
50  * input queue processing does not use jtag_read_buffer() to avoid unnecessary overhead\r
51  * also the buffer for incomming data is reallocated only if necessary\r
52  * no parameters, makes use of stored state information\r
53  */\r
54 void bitq_in_proc(void)\r
55 {\r
56         /* static information preserved between calls to increase performance */\r
57         static u8 *in_buff; /* pointer to buffer for scanned data */\r
58         static int in_idx; /* index of byte being scanned */\r
59         static u8 in_mask; /* mask of next bit to be scanned */\r
60 \r
61         scan_field_t *field;\r
62         int tdo;\r
63 \r
64         /* loop through the queue */\r
65         while (bitq_in_state.cmd) {\r
66                 /* only JTAG_SCAN command may return data */\r
67                 if (bitq_in_state.cmd->type==JTAG_SCAN) {\r
68                         /* loop through the fields */\r
69                         while (bitq_in_state.field_idx<bitq_in_state.cmd->cmd.scan->num_fields) {\r
70 \r
71                                 field=&bitq_in_state.cmd->cmd.scan->fields[bitq_in_state.field_idx];\r
72                                 if ( field->in_value || field->in_handler) {\r
73 \r
74                                         if (bitq_in_state.bit_pos==0) {\r
75                                                 /* initialize field scanning */\r
76                                                 in_mask=0x01;\r
77                                                 in_idx=0;\r
78                                                 if (field->in_value) in_buff=field->in_value;\r
79                                                 else {\r
80                                                         /* buffer reallocation needed? */\r
81                                                         if (field->num_bits>bitq_in_bufsize*8) {\r
82                                                                 /* buffer previously allocated? */\r
83                                                                 if (bitq_in_buffer!=NULL) {\r
84                                                                         /* free it */\r
85                                                                         free(bitq_in_buffer);\r
86                                                                         bitq_in_buffer=NULL;\r
87                                                                 }\r
88                                                                 /* double the buffer size until it fits */\r
89                                                                 while (field->num_bits>bitq_in_bufsize*8) bitq_in_bufsize*=2;\r
90                                                         }\r
91                                                         /* if necessary, allocate buffer and check for malloc error */\r
92                                                         if (bitq_in_buffer==NULL && (bitq_in_buffer=malloc(bitq_in_bufsize))==NULL) {\r
93                                                                 ERROR("malloc error");\r
94                                                                 exit(-1);\r
95                                                         }\r
96                                                         in_buff=(void *)bitq_in_buffer;\r
97                                                 }\r
98                                         }\r
99 \r
100                                         /* field scanning */\r
101                                         while (bitq_in_state.bit_pos<field->num_bits) {\r
102                                                 if ((tdo=bitq_interface->in())<0) {\r
103 #ifdef _DEBUG_JTAG_IO_\r
104                                                         DEBUG("bitq in EOF");\r
105 #endif\r
106                                                         return;\r
107                                                 }\r
108                                                 if (in_mask==0x01) in_buff[in_idx]=0;\r
109                                                 if (tdo) in_buff[in_idx]|=in_mask;\r
110                                                 if (in_mask==0x80) {\r
111                                                         in_mask=0x01;\r
112                                                         in_idx++;\r
113                                                 }\r
114                                                 else in_mask<<=1;\r
115                                                 bitq_in_state.bit_pos++;\r
116                                         }\r
117 \r
118 \r
119                                         if (field->in_handler && bitq_in_state.status==ERROR_OK) {\r
120                                                 bitq_in_state.status=(*field->in_handler)(in_buff, field->in_handler_priv, field);\r
121                                         }\r
122 \r
123                                 }\r
124 \r
125                                 bitq_in_state.field_idx++; /* advance to next field */\r
126                                 bitq_in_state.bit_pos=0; /* start next field from the first bit */\r
127                         }\r
128 \r
129                 }\r
130                 bitq_in_state.cmd=bitq_in_state.cmd->next; /* advance to next command */\r
131                 bitq_in_state.field_idx=0; /* preselect first field */\r
132         }\r
133 }\r
134 \r
135 \r
136 \r
137 void bitq_io(int tms, int tdi, int tdo_req)\r
138 {\r
139         bitq_interface->out(tms, tdi, tdo_req);\r
140         /* check and process the input queue */\r
141         if (bitq_interface->in_rdy()) bitq_in_proc();\r
142 }\r
143 \r
144 \r
145 void bitq_end_state(enum tap_state state)\r
146 {\r
147         if (state==-1) return;\r
148         if (tap_move_map[state]==-1) {\r
149                 ERROR("BUG: %i is not a valid end state", state);\r
150                 exit(-1);\r
151         }\r
152         end_state = state;\r
153 }\r
154 \r
155 \r
156 void bitq_state_move(enum tap_state new_state)\r
157 {\r
158         int i=0;\r
159         u8 tms_scan;\r
160 \r
161         if (tap_move_map[cur_state]==-1 || tap_move_map[new_state]==-1) {\r
162                 ERROR("TAP move from or to unstable state");\r
163                 exit(-1);\r
164         }\r
165 \r
166         tms_scan=TAP_MOVE(cur_state, new_state);\r
167 \r
168         for (i=0; i<7; i++) {\r
169                 bitq_io(tms_scan&1, 0, 0);\r
170                 tms_scan>>=1;\r
171         }\r
172 \r
173         cur_state = new_state;\r
174 }\r
175 \r
176 \r
177 void bitq_path_move(pathmove_command_t *cmd)\r
178 {\r
179         int i;\r
180 \r
181         for (i=0; i<=cmd->num_states; i++) {\r
182                 if (tap_transitions[cur_state].low == cmd->path[i]) bitq_io(0, 0, 0);\r
183                 else if (tap_transitions[cur_state].high == cmd->path[i]) bitq_io(1, 0, 0);\r
184                 else {\r
185                         ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[i]]);\r
186                         exit(-1);\r
187                 }\r
188 \r
189                 cur_state = cmd->path[i];\r
190         }\r
191 \r
192         end_state = cur_state;\r
193 }\r
194 \r
195 \r
196 void bitq_runtest(int num_cycles)\r
197 {\r
198         int i;\r
199 \r
200         /* only do a state_move when we're not already in RTI */\r
201         if (cur_state != TAP_RTI) bitq_state_move(TAP_RTI);\r
202 \r
203         /* execute num_cycles */\r
204         for (i = 0; i < num_cycles; i++)\r
205                 bitq_io(0, 0, 0);\r
206 \r
207         /* finish in end_state */\r
208         if (cur_state != end_state) bitq_state_move(end_state);\r
209 }\r
210 \r
211 \r
212 void bitq_scan_field(scan_field_t *field, int pause)\r
213 {\r
214         int bit_cnt;\r
215         int tdo_req;\r
216 \r
217         u8 *out_ptr;\r
218         u8 out_mask;\r
219 \r
220         if ( field->in_value || field->in_handler) tdo_req=1;\r
221         else tdo_req=0;\r
222 \r
223         if (field->out_value==NULL) {\r
224                 /* just send zeros and request data from TDO */\r
225                 for (bit_cnt=field->num_bits; bit_cnt>1; bit_cnt--)\r
226                         bitq_io(0, 0, tdo_req);\r
227                 bitq_io(pause, 0, tdo_req);\r
228         }\r
229         else {\r
230                 /* send data, and optionally request TDO */\r
231                 out_mask=0x01;\r
232                 out_ptr=field->out_value;\r
233                 for (bit_cnt=field->num_bits; bit_cnt>1; bit_cnt--) {\r
234                         bitq_io(0, ((*out_ptr)&out_mask)!=0, tdo_req);\r
235                         if (out_mask==0x80) {\r
236                                 out_mask=0x01;\r
237                                 out_ptr++;\r
238                         }\r
239                         else out_mask<<=1;\r
240                 }\r
241                 bitq_io(pause, ((*out_ptr)&out_mask)!=0, tdo_req);\r
242         }\r
243 \r
244         if (pause) {\r
245                 bitq_io(0,0,0);\r
246                 if (cur_state==TAP_SI) cur_state=TAP_PI;\r
247                 else if (cur_state==TAP_SD) cur_state=TAP_PD;\r
248         }\r
249 }\r
250 \r
251 \r
252 void bitq_scan(scan_command_t *cmd)\r
253 {\r
254         int i;\r
255 \r
256         if (cmd->ir_scan) bitq_state_move(TAP_SI);\r
257         else bitq_state_move(TAP_SD);\r
258 \r
259         for (i=0; i < cmd->num_fields-1; i++)\r
260                 bitq_scan_field(&cmd->fields[i], 0);\r
261         bitq_scan_field(&cmd->fields[i], 1);\r
262 }\r
263 \r
264 \r
265 int bitq_execute_queue(void)\r
266 {\r
267         jtag_command_t *cmd = jtag_command_queue; /* currently processed command */\r
268 \r
269         bitq_in_state.cmd = jtag_command_queue;\r
270         bitq_in_state.field_idx = 0;\r
271         bitq_in_state.bit_pos = 0;\r
272         bitq_in_state.status = ERROR_OK;\r
273 \r
274         while (cmd) {\r
275 \r
276                 switch (cmd->type) {\r
277 \r
278                         case JTAG_END_STATE:\r
279 #ifdef _DEBUG_JTAG_IO_\r
280                                 DEBUG("end_state: %i", cmd->cmd.end_state->end_state);\r
281 #endif\r
282                                 bitq_end_state(cmd->cmd.end_state->end_state);\r
283                                 break;\r
284 \r
285                         case JTAG_RESET:\r
286 #ifdef _DEBUG_JTAG_IO_\r
287                                 DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);\r
288 #endif\r
289                                 bitq_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);\r
290                                 if (bitq_interface->in_rdy()) bitq_in_proc();\r
291                                 break;\r
292 \r
293                         case JTAG_RUNTEST:\r
294 #ifdef _DEBUG_JTAG_IO_\r
295                                 DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);\r
296 #endif\r
297                                 bitq_end_state(cmd->cmd.runtest->end_state);\r
298                                 bitq_runtest(cmd->cmd.runtest->num_cycles);\r
299                                 break;\r
300 \r
301                         case JTAG_STATEMOVE:\r
302 #ifdef _DEBUG_JTAG_IO_\r
303                                 DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);\r
304 #endif\r
305                                 bitq_end_state(cmd->cmd.statemove->end_state);\r
306                                 bitq_state_move(end_state); /* uncoditional TAP move */\r
307                                 break;\r
308 \r
309                         case JTAG_PATHMOVE:\r
310 #ifdef _DEBUG_JTAG_IO_\r
311                                 DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);\r
312 #endif\r
313                                 bitq_path_move(cmd->cmd.pathmove);\r
314                                 break;\r
315 \r
316                         case JTAG_SCAN:\r
317 #ifdef _DEBUG_JTAG_IO_\r
318                                 DEBUG("scan end in %i", cmd->cmd.scan->end_state);\r
319                                 if (cmd->cmd.scan->ir_scan) DEBUG("scan ir");\r
320                                 else DEBUG("scan dr");\r
321 #endif\r
322                                 bitq_end_state(cmd->cmd.scan->end_state);\r
323                                 bitq_scan(cmd->cmd.scan);\r
324                                 if (cur_state != end_state) bitq_state_move(end_state);\r
325                                 break;\r
326 \r
327                         case JTAG_SLEEP:\r
328 #ifdef _DEBUG_JTAG_IO_\r
329                                 DEBUG("sleep %i", cmd->cmd.sleep->us);\r
330 #endif\r
331                                 bitq_interface->sleep(cmd->cmd.sleep->us);\r
332                                 if (bitq_interface->in_rdy()) bitq_in_proc();\r
333                                 break;\r
334 \r
335                         default:\r
336                                 ERROR("BUG: unknown JTAG command type encountered");\r
337                                 exit(-1);\r
338                 }\r
339 \r
340                 cmd = cmd->next;\r
341         }\r
342 \r
343         bitq_interface->flush();\r
344         bitq_in_proc();\r
345 \r
346         if (bitq_in_state.cmd) {\r
347                 ERROR("missing data from bitq interface");\r
348                 return ERROR_JTAG_QUEUE_FAILED;\r
349         }\r
350         if (bitq_interface->in()>=0) {\r
351                 ERROR("extra data from bitq interface");\r
352                 return ERROR_JTAG_QUEUE_FAILED;\r
353         }\r
354 \r
355         return bitq_in_state.status;\r
356 }\r
357 \r
358 \r
359 void bitq_cleanup(void)\r
360 {\r
361         if (bitq_in_buffer!=NULL)\r
362         {\r
363                 free(bitq_in_buffer);\r
364                 bitq_in_buffer=NULL;\r
365         }\r
366 }\r