1 /* XCF Flash PROM JTAG programming algorithms
2
3 Copyright (C) 2004-2011 Andrew Rogers
4 2009 Uwe Bonnes
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 Changes:
21 Dmitry Teytelman [dimtey@gmail.com] 14 Jun 2006 [applied 13 Aug 2006]:
22 Code cleanup for clean -Wall compile.
23 */
24
25 #include <string.h>
26 #include <stdexcept>
27 #include "progalgxcf.h"
28 #include "utilities.h"
29
30 const byte ProgAlgXCF::SERASE=0x0a;
31 const byte ProgAlgXCF::ISCTESTSTATUS=0xe3;
32 const byte ProgAlgXCF::ISC_ENABLE=0xe8;
33 const byte ProgAlgXCF::ISC_PROGRAM=0xea;
34 const byte ProgAlgXCF::ISC_ADDRESS_SHIFT=0xeb;
35 const byte ProgAlgXCF::ISC_ERASE=0xec;
36 const byte ProgAlgXCF::ISC_DATA_SHIFT=0xed;
37 const byte ProgAlgXCF::CONFIG=0xee;
38 const byte ProgAlgXCF::ISC_READ=0xef;
39 const byte ProgAlgXCF::ISC_DISABLE=0xf0;
40 const byte ProgAlgXCF::IDCODE=0xfe;
41 const byte ProgAlgXCF::BYPASS=0xff;
42
43 const byte ProgAlgXCF::BIT3=0x08;
44 const byte ProgAlgXCF::BIT4=0x10;
45
46 static const unsigned int MAX_BLOCK_SIZE = 4096;
47 static const unsigned int FRAMES_PER_BLOCK = 32;
48
49
ProgAlgXCF(Jtag & j,int size_ind)50 ProgAlgXCF::ProgAlgXCF(Jtag &j, int size_ind)
51 {
52 use_optimized_algs = false;
53
54 switch (size_ind & 0xfffffef) /* part number of XC18V has X in bitmask */
55 {
56 case 0x23:
57 size = 1<<19;
58 block_size = 2048;
59 break;
60 case 0x24:
61 size = 1<<20;
62 block_size = 2048;
63 break;
64 case 0x25:
65 size = 2<<20;
66 block_size = 4096;
67 break;
68 case 0x26:
69 size = 4<<20;
70 block_size = 4096;
71 break;
72 case 0x44:
73 size = 1<<20;
74 block_size = 2048;
75 use_optimized_algs = true;
76 break;
77 case 0x45:
78 size = 2<<20;
79 block_size = 4096;
80 use_optimized_algs = true;
81 break;
82 case 0x46:
83 size = 4<<20;
84 block_size = 4096;
85 use_optimized_algs = true;
86 break;
87 default:
88 fprintf(stderr,"Unknown XCF device size code %x\n", size_ind);
89 throw std::invalid_argument("Unknown XCF device size code");
90 }
91
92 jtag=&j;
93 }
94 /* For XCF, implement "xflow_erase_optimized" for the serial devices
95 * from the XCF..1532.bsd" files
96 * and for XC18V flow_erase
97 */
98
erase()99 int ProgAlgXCF::erase()
100 {
101 byte data[4];
102 int i;
103 byte ircap[1];
104
105 Timer timer;
106 jtag->shiftIR(&ISC_DISABLE);
107 jtag->Usleep(110000);
108 jtag->shiftIR(&BYPASS,ircap);
109 if((ircap[0]&BIT3)==BIT3){
110 fprintf(stderr,"Device is write protected! Aborting\n");
111 return 1;
112 }
113 jtag->shiftIR(&ISC_ENABLE);
114 if (! use_optimized_algs)
115 data[0]=0x34;
116 else
117 data[0]=0x37;
118 jtag->shiftDR(data,0,6);
119 jtag->shiftIR(&ISC_ADDRESS_SHIFT);
120 jtag->longToByteArray(1,data);
121 jtag->shiftDR(data,0,16);
122 jtag->cycleTCK(1);
123
124 if(jtag->getVerbose())
125 {
126 fprintf(stderr, "Erasing");
127 fflush(stderr);
128 }
129 jtag->shiftIR(&ISC_ERASE);
130
131 for(i=0; i<32;i++)
132 {
133 byte xcstatus[1];
134 if(jtag->getVerbose())
135 {
136 fprintf(stderr, ".");
137 fflush(stderr);
138 }
139 jtag->Usleep(500000);
140 if (! use_optimized_algs)
141 {
142 if (i == 31)
143 break;
144 }
145 else
146 {
147 jtag->shiftIR(&ISCTESTSTATUS);
148 jtag->shiftDR(0,xcstatus,8);
149 if (xcstatus[0] & 0x04)
150 break;
151 }
152 }
153 if (i > 31)
154 {
155 fprintf(stderr,"\nErased failed! Aborting\n");
156 return 1;
157 }
158
159 if (jtag->getVerbose())
160 fprintf(stderr, "done\nErase time %.1f ms\n", timer.elapsed() * 1.0e3);
161
162 return 0;
163 }
164
program(BitFile & file)165 int ProgAlgXCF::program(BitFile &file)
166 {
167 byte data[MAX_BLOCK_SIZE/8];
168 unsigned int skipbits, nbits;
169
170 skipbits = file.getOffset() * 8;
171 if (skipbits % block_size != 0)
172 {
173 fprintf(stderr, "Programming does not start at block boundary (offset = %u bits), aborting\n", skipbits);
174 return -1;
175 }
176 if (skipbits > size)
177 {
178 fprintf(stderr,"Program start outside PROM area (offset = %u bits), aborting\n", skipbits);
179 return -1;
180 }
181
182 if (file.getRLength() != 0)
183 nbits = file.getRLength() * 8;
184 else
185 nbits = file.getLength();
186
187 if (nbits > size - skipbits)
188 {
189 fprintf(stderr,"Program outside PROM areas requested, clipping\n");
190 nbits = size - skipbits;
191 }
192
193 if (nbits % block_size != 0)
194 fprintf(stderr, "Programming does not end at block boundary (nbits = %u), padding\n", nbits);
195
196 unsigned int skipblocks = skipbits / block_size;
197 unsigned int nblocks = (nbits + block_size - 1) / block_size;
198
199 Timer timer;
200 jtag->shiftIR(&ISC_DISABLE);
201 jtag->Usleep(1000);
202 jtag->setTapState(Jtag::TEST_LOGIC_RESET);
203 jtag->shiftIR(&ISC_ENABLE);
204 if (! use_optimized_algs)
205 data[0]=0x34;
206 else
207 data[0]=0x37;
208 jtag->shiftDR(data,0,6);
209
210 for (unsigned int i = 0; i < nblocks; i++)
211 {
212 unsigned int frame = (skipblocks + i) * FRAMES_PER_BLOCK;
213 int j;
214
215 if (jtag->getVerbose())
216 {
217 fprintf(stderr, "\rProgramming block %6u/%6u at XCF frame 0x%04x",
218 i, nblocks, frame);
219 fflush(stderr);
220 }
221
222 jtag->shiftIR(&ISC_DATA_SHIFT);
223 if ((i+1) * block_size <= nbits)
224 {
225 jtag->shiftDR(&(file.getData())[i*block_size/8], 0, block_size);
226 }
227 else
228 {
229 unsigned int rembytes = (nbits - (i * block_size) + 7) / 8;
230 unsigned int padbytes = block_size / 8 - rembytes;
231 memset(data, 0xff, padbytes);
232 jtag->shiftDR(&(file.getData())[i*block_size/8], 0, rembytes*8, 0, false);
233 jtag->shiftDR(data, 0, padbytes*8);
234 }
235
236 jtag->longToByteArray(frame, data);
237 jtag->shiftIR(&ISC_ADDRESS_SHIFT);
238 jtag->cycleTCK(1);
239 jtag->shiftDR(data,0,16);
240 jtag->cycleTCK(1);
241 jtag->shiftIR(&ISC_PROGRAM);
242
243 if (! use_optimized_algs)
244 {
245 jtag->Usleep(14000);
246 }
247 else
248 {
249 for (j = 0; j < 28; j++)
250 {
251 byte xcstatus[1];
252 jtag->Usleep(500);
253 jtag->shiftIR(&ISCTESTSTATUS);
254 jtag->shiftDR(0,xcstatus,8);
255 if (xcstatus[0] & 0x04)
256 break;
257 else if(jtag->getVerbose())
258 {
259 fprintf(stderr, ".");
260 fflush(stderr);
261 }
262 }
263 if (j == 28)
264 {
265 fprintf(stderr,"\nProgramming block %u (frame 0x%04x) failed! Aborting\n", i, frame);
266 return 1;
267 }
268 }
269 }
270
271 if (! use_optimized_algs) /* only on XC18V*/
272 {
273 jtag->shiftIR(&ISC_ADDRESS_SHIFT);
274 jtag->cycleTCK(1);
275 jtag->longToByteArray(1,data);
276 jtag->shiftDR(data, 0, 16);
277 jtag->cycleTCK(1);
278 jtag->shiftIR(&SERASE);
279 jtag->Usleep(37000);
280 }
281
282 if (jtag->getVerbose())
283 fprintf(stderr, "done\nProgramming time %.1f ms\n", timer.elapsed() * 1.0e3);
284
285 jtag->shiftIR(&BYPASS);
286 jtag->cycleTCK(1);
287 jtag->tapTestLogicReset();
288
289 return 0;
290 }
291
verify(BitFile & file)292 int ProgAlgXCF::verify(BitFile &file)
293 {
294 byte data[MAX_BLOCK_SIZE/8];
295 unsigned int skipbits, nbits;
296
297 skipbits = file.getOffset() * 8;
298 if (skipbits % block_size != 0)
299 {
300 fprintf(stderr, "Verify does not start at block boundary (offset = %u bits), aborting\n", skipbits);
301 return 1;
302 }
303 if (skipbits > size)
304 {
305 fprintf(stderr,"Verify start outside PROM area (offset = %u bits), aborting\n", skipbits);
306 return -1;
307 }
308
309 if (file.getRLength() != 0)
310 nbits = file.getRLength() * 8;
311 else
312 nbits = file.getLength();
313
314 if (nbits > size - skipbits)
315 {
316 fprintf(stderr,"Verify outside PROM areas requested, clipping\n");
317 nbits = size - skipbits;
318 }
319
320 unsigned int skipblocks = skipbits / block_size;
321 unsigned int nblocks = (nbits + block_size - 1) / block_size;
322
323 Timer timer;
324 jtag->setTapState(Jtag::TEST_LOGIC_RESET);
325 jtag->shiftIR(&ISC_ENABLE);
326 data[0]=0x34;
327 jtag->shiftDR(data,0,6);
328
329 for (unsigned int i = 0; i < nblocks; i++)
330 {
331 unsigned int frame = (skipblocks + i) * FRAMES_PER_BLOCK;
332 int res;
333
334 if(jtag->getVerbose())
335 {
336 fprintf(stderr, "\rVerify block %6u/%6u at XCF frame 0x%04x",
337 i, nblocks, frame);
338 fflush(stderr);
339 }
340
341 jtag->longToByteArray(frame,data);
342 jtag->shiftIR(&ISC_ADDRESS_SHIFT);
343 jtag->shiftDR(data,0,16);
344 jtag->cycleTCK(1);
345 jtag->shiftIR(&ISC_READ);
346 jtag->Usleep(50);
347 jtag->shiftDR(0,data,block_size);
348
349 unsigned int blkbytes = block_size / 8;
350 if ((i + 1) * block_size > nbits)
351 blkbytes = (nbits - (i * block_size) + 7) / 8;
352 res = memcmp(data, &(file.getData())[i*block_size/8], blkbytes);
353 if (res)
354 {
355 fprintf(stderr, "\nVerify failed at block %u (frame 0x%04x)\n",
356 i, frame);
357 return res;
358 }
359 }
360
361 if (jtag->getVerbose())
362 fprintf(stderr, "\nSuccess! Verify time %.1f ms\n", timer.elapsed() * 1.0e3);
363
364 jtag->tapTestLogicReset();
365
366 return 0;
367 }
368
read(BitFile & file)369 int ProgAlgXCF::read(BitFile &file)
370 {
371 byte data[MAX_BLOCK_SIZE/8];
372 unsigned int skipbits, nbits;
373
374 skipbits = file.getOffset() * 8;
375 if (skipbits % block_size != 0)
376 {
377 fprintf(stderr, "Read does not start at block boundary (offset = %u bits), aborting\n", skipbits);
378 return -1;
379 }
380 if (skipbits > size)
381 {
382 fprintf(stderr,"Read start outside PROM area (offset = %u bits), aborting\n", skipbits);
383 return -1;
384 }
385
386 if (file.getRLength() != 0)
387 nbits = file.getRLength() * 8;
388 else
389 nbits = size - skipbits;
390
391 if (nbits > size - skipbits)
392 {
393 fprintf(stderr,"Read outside PROM areas requested, clipping\n");
394 nbits = size - skipbits;
395 }
396
397 unsigned int skipblocks = skipbits / block_size;
398 unsigned int nblocks = (nbits + block_size - 1) / block_size;
399
400 file.setLength(nbits);
401
402 Timer timer;
403 jtag->setTapState(Jtag::TEST_LOGIC_RESET);
404 jtag->shiftIR(&ISC_ENABLE);
405 data[0]=0x34;
406 jtag->shiftDR(data,0,6);
407
408 for (unsigned int i = 0; i < nblocks; i++)
409 {
410 unsigned int frame = (skipblocks + i) * FRAMES_PER_BLOCK;
411
412 if(jtag->getVerbose())
413 {
414 fprintf(stderr, "\rReading block %6u/%6u at XCF frame 0x%04x",
415 i, nblocks, frame);
416 fflush(stderr);
417 }
418
419 jtag->longToByteArray(frame,data);
420 jtag->shiftIR(&ISC_ADDRESS_SHIFT);
421 jtag->shiftDR(data,0,16);
422 jtag->cycleTCK(1);
423 jtag->shiftIR(&ISC_READ);
424 jtag->Usleep(50);
425 jtag->shiftDR(0,data,block_size);
426
427 unsigned int blkbytes = block_size / 8;
428 if ((i + 1) * block_size > nbits)
429 blkbytes = (nbits - (i * block_size) + 7) / 8;
430 memcpy(&(file.getData())[i*block_size/8], data, blkbytes);
431 }
432
433 if (jtag->getVerbose())
434 fprintf(stderr, "\nSuccess! Read time %.1f ms\n", timer.elapsed() * 1.0e3);
435
436 jtag->tapTestLogicReset();
437
438 return 0;
439 }
440
disable()441 void ProgAlgXCF::disable()
442 {
443 jtag->shiftIR(&ISC_DISABLE);
444 jtag->Usleep(110000);
445 jtag->shiftIR(&BYPASS);
446 jtag->cycleTCK(1);
447 jtag->tapTestLogicReset();
448 }
449
reconfig(void)450 void ProgAlgXCF::reconfig(void)
451 {
452 jtag->shiftIR(&CONFIG);
453 jtag->cycleTCK(1);
454 jtag->shiftIR(&BYPASS);
455 jtag->cycleTCK(1);
456 jtag->tapTestLogicReset();
457 }
458