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