-
Notifications
You must be signed in to change notification settings - Fork 51
/
adapter-bitbang.c
1337 lines (1141 loc) · 46.6 KB
/
adapter-bitbang.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// last edited: Sunday, 30 August, 2015 (release 3)
/*
* Interface to PIC32 ICSP port using bitbang adapter.
* Copyright (C) 2014 Serge Vakulenko
*
* Additions for talking to ascii ICSP programmer Copyright (C) 2015 Robert Rozee
*
* This file is part of PIC32PROG project, which is distributed
* under the terms of the GNU General Public License (GPL).
* See the accompanying file "COPYING" for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include "adapter.h"
#include "pic32.h"
#include "serial.h"
typedef struct {
adapter_t adapter; /* Common part */
int BitsToRead; // number of 'bits' waiting in Rx buffer
int CharToRead; // number of characters the bits are encoded into
int PendingHandshake; // indicates a return handshake is expected
unsigned TotalCodeChrsSent; // count of total # of code characters sent out
unsigned TotalCodeChrsRecv; // count of total # of code characters received
unsigned TotalBitPairsSent; // count of total # of TDI and TMS pairs sent
unsigned TotalBitsReceived; // count of total # of TDO bits recieved
unsigned MaxBufferedWrites; // max continuous characters written before read
unsigned RunningWriteCount; // running count of characters written, reset by read
unsigned WriteCount; // number of calls to serial_write
unsigned Read1Count; // number of calls to serial_read (data)
unsigned Read2Count; // number of calls to serial_read (handshakes)
unsigned FDataCount; // number of calls to xfer_fastdata
unsigned DelayCount[4]; // number of calls to delay10mS (erase, xfer inst, PE resp, other)
struct timeval T1, T2; // record start and finishing timestamps
unsigned use_executive;
unsigned serial_execution_mode;
} bitbang_adapter_t;
static int DBG1 = 0; // add format characters to command strings, print out
static int DBG2 = 0; // print messages at entry to main routines
static int DBG3 = 0; // print our row program parameters
static int CFG1 = 2; // 1/2 configure for 64/1024 byte buffer in programming adapter
static int CFG2 = 1; // 1/2 config to retrieve PrAcc and alert if (PrAcc != 1)
// (note: option 2 doubles programming time)
static int CFG3 = 1; // 0 = uncompressed stream (use only 'd','e','f','g'
// 1 = use 4-bit packing (on data only) 'i'-'x','I'-'X','a','z','A'
static int CFG4 = 1; // decompression method in serial read (normally set to match CFG3)
static int MAXW = 440; // maximum continuous write before sync: 900 + 50 < 1024, 440 + 30 < 512
/*
* Calculate checksum.
*/
static unsigned calculate_crc(unsigned crc, unsigned char *data, unsigned nbytes)
{
static const unsigned short crc_table [16] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
};
unsigned i;
while (nbytes--) {
i = (crc >> 12) ^ (*data >> 4);
crc = crc_table[i & 0x0F] ^ (crc << 4);
i = (crc >> 12) ^ (*data >> 0);
crc = crc_table[i & 0x0F] ^ (crc << 4);
data++;
}
return crc & 0xffff;
}
/*
* Sends a command ('8')to the programmer telling it to insert
* a 10mS delay in the datastream being sent to the target. This
* is the only reliable way to create a delay at the target.
* (by RR)
*/
static void bitbang_delay10mS(bitbang_adapter_t *a, int caller)
{
unsigned char ch;
ch = '8';
serial_write(&ch, 1);
a->WriteCount++;
a->DelayCount[caller]++;
}
/*
* Current version of bitbang_send, sends a string of data out to the target encoded
* as ASCII characters to be interpreted by an intellenent ICSP programmer.
*
* NOTE: this version of pic32prog implements the 2-wire communications mode via the
* ICSP port. This means we need to encode TDI, TMS, and read_flag into one character,
* sending all three out at once to an Arduino NANO acting as an intelligent programmer.
* If read_flag is set, then the programmer needs to respond with a series of characters
* indicating the values of TDO that the target responds with.
*
* Below is the currently implemented command set:
*
* 'd' : TDI = 0, TMS = 0, read_flag = 0 0x64
* 'e' : TDI = 0, TMS = 1, read_flag = 0
* 'f' : TDI = 1, TMS = 0, read_flag = 0
* 'g' : TDI = 1, TMS = 1, read_flag = 0
*
* 'a' : data header
* 'z' : data footer
* 'i'..'x' : 4 TDI bits encoded, TMS = 0, read_flag = 0
*
* 'D' : TDI = 0, TMS = 0, read_flag = 1 0x44
* 'E' : TDI = 0, TMS = 1, read_flag = 1
* 'F' : TDI = 1, TMS = 0, read_flag = 1
* 'G' : TDI = 1, TMS = 1, read_flag = 1
*
* 'A' : data header with read_flag = 1 on last bit
* 'I'..'X' : 4 TDI bits encoded, TMS = 0, read_flag = 1
*
* '.' : no operation, used for formatting
* '>' : request sync response - '<'
*
* '0' : clock out a 0 on PGD pin
* '1' : clock out a 1 on PGD pin
* '2' : set MCLR low
* '3' : set MCLR high
* '4' : turn target power off
* '5' : turn target power on
* '8' : insert 10mS delay
* '?' : return ID string, "ascii JTAG XN"
*
* if the request is 'D'..'G', then respond with '0'/'1' to indicate TDO = 0/1
* if the request is 'I'..'X', then respond with 'I'..'X' encoding 4 TDO bits
*
* (by RR)
*/
static void bitbang_send(bitbang_adapter_t *a,
unsigned tms_nbits, unsigned tms,
unsigned tdi_nbits, unsigned long long tdi, int read_flag)
{
//
// TMS is a command of 0 to 14 bits length, sent LSB first. TDI = 0 throughout.
//
// if nTDI<>0 then send TMS = 1-0-0 (TDI = 0).
//
// Next we send out the TDI bits (up to 64, LSB first), with TMS=0 for n-1 bits;
// the last TDI bit should be accompanied with TMS = 1.
//
// if nTDI<>0 then send TMS = 1-0 (TDI = 0).
//
// NOTE: if read_flag == 1, then read TDO on last TMS bit and each of n-1 TDI bits.
// if read_flag == 2, only read TDO on the last TMS bit (to just get PrAcc)
//
unsigned char buffer[110]; // @@@@@@@@@@ BUFFERED WRITES VERSION @@@@@@@@@@
int index = 0; // index of next slot to use in buffer
int pairs = 0; // count of number of TDI/TMS pairs
int count = 0; // count of the number of symbols used
int i, n;
unsigned char ch;
if (a->BitsToRead != 0)
fprintf(stderr, "WARNING - write while pending read (in send)\n");
if (read_flag && (tdi_nbits == 0))
fprintf(stderr, "WARNING - request to read 0 bits (in send)\n");
for (i = tms_nbits; i > 0; i--) { // for each of the n bits...
ch = (tms & 1) + 'd'; // d, e, f, g
buffer [index++] = ch; // append to buffer
tms >>= 1; // shift TMS right one bit
}
count += tms_nbits;
pairs += tms_nbits;
if (DBG1 && (tms_nbits != 0))
buffer[index++] = '.'; // spacer, ignored by programmer
if (tdi_nbits != 0) { // 1-0-0 if nTDI <> 0
if (CFG3) { // use compression: edd -> a, edD -> A
buffer[index++] = (read_flag ? 'A' : 'a');
count++;
}
else { // compression flag turned off
ch = 1 + 'd';
buffer[index++] = ch;
ch = 0 + 'd';
buffer[index++] = ch;
ch = 0 + (read_flag ? 'D' : 'd');
buffer[index++] = ch;
count += 3;
}
pairs += 3;
if (DBG1)
buffer[index++] = '.'; // spacer, ignored by programmer
}
long long Xtdi = tdi;
a->CharToRead = (read_flag == 2 ? 1 : 0);
a->BitsToRead = (read_flag == 2 ? 1 : 0);
i = tdi_nbits;
if (CFG3) { // while we can, package up lots of 4 TDI bits
for (; i > 4; i -= 4) { // make sure the last bit is NOT packaged
ch = (read_flag == 1 ? 'I' : 'i') + (tdi & 0xF);
buffer[index++] = ch;
tdi >>= 4;
count++;
if (read_flag == 1) a->CharToRead++;
}
}
for (; i > 0; i--) { // (send all/remaining bits as singles)
ch = ((tdi & 1) << 1) + (i == 1) + // TMS=0 for n-1 bits, then 1 on last bit
((read_flag == 1 && i != 1) ? // 0 = no read, 1 = normal read, 2 = oPrAcc read
'D' : 'd'); // UC = read, LC = none, no read on last bit
buffer[index++] = ch; // append to buffer
tdi >>= 1; // shift TDI right one bit
count++;
if (read_flag == 1) a->CharToRead++;
}
pairs += tdi_nbits;
if (read_flag == 1) a->BitsToRead = tdi_nbits;
if (tdi_nbits != 0) { // 1-0 if nTDI <> 0
if (DBG1)
buffer[index++] = '.'; // spacer, ignored by programmer
if (CFG3) {
buffer[index++] ='z'; // use compression: ed -> z
count++;
}
else { // compression flag turned off
ch = 1 + 'd';
buffer[index++] = ch;
ch = 0 + 'd';
buffer[index++] = ch;
count += 2;
}
pairs += 2;
}
//
// Control handshaking for ICSP programmers
//
if (a->PendingHandshake)
{
//////// this code is also duplicated in bitbang_send ////////
if (a->RunningWriteCount > a->MaxBufferedWrites)
a->MaxBufferedWrites = a->RunningWriteCount;
a->RunningWriteCount = 0;
//////////////////////////////////////////////////////////////
a->PendingHandshake = 0;
n = serial_read(&ch, 1, 250);
a->Read2Count++;
if (n != 1 || ch != '<')
fprintf(stderr, "WARNING - handshake read error (in send)\n");
}
//
// the below block is to implement handshake on
// EVERY write that does not have (read_flag != 0)
//
if (CFG1 == 1 && !read_flag)
{
buffer[index++] = '>';
a->PendingHandshake = 1;
}
//
// this block is to implement handshake on every 900/440 (MAXW) characters
// NOTE: assumes the Rx buffer in the programmer is 1024/512 bytes long
// **************
if (CFG1 == 2 && !read_flag && (a->RunningWriteCount + index) > MAXW) // 900 + 50 < 1024
{ // 440 + 30 < 512
buffer[index++] = '>';
a->PendingHandshake = 1;
}
//
// end of handshaking code
//
buffer[index] = 0; // append trailing zero so can print as a string
a->RunningWriteCount += index; // number of characters being written
a->TotalBitPairsSent += pairs; // number of TDI/TMS pairs encoded
a->TotalCodeChrsSent += count; // number of symbols used to send pairs
if (DBG1) {
unsigned L4 = Xtdi >> 48;
unsigned L3 = (Xtdi >> 32) & 0xFFFF;
unsigned L2 = (Xtdi >> 16) & 0xFFFF;
unsigned L1 = Xtdi & 0xFFFF;
printf("n=%i, <%s> read=%i TDI: %04x %04x %04x %04x\n",
index, buffer, read_flag, L4, L3, L2, L1);
}
serial_write(buffer, index);
a->WriteCount++;
}
/*
* (by RR)
*/
static unsigned long long bitbang_recv(bitbang_adapter_t *a)
{
unsigned char buffer[70];
unsigned long long word;
int n, i;
//////// this code is also duplicated in bitbang_send ////////
if (a->RunningWriteCount > a->MaxBufferedWrites)
a->MaxBufferedWrites = a->RunningWriteCount;
a->RunningWriteCount = 0;
//////////////////////////////////////////////////////////////
if (a->PendingHandshake)
fprintf(stderr, "WARNING - handshake pending error (in recv)\n");
int expected = (CFG4 ? a->CharToRead : a->BitsToRead);
n = serial_read(buffer, expected, 250);
a->TotalCodeChrsRecv += n;
a->Read1Count++;
buffer[n] = 0; // append trailing zero so can print as a string
if (n != expected)
fprintf(stderr,
"WARNING - fewer characters read (%i) than expected (%i) (in recv)\n",
n, expected);
word = 0;
for (i = n-1; i >=0; i--) {
if ((buffer[i] >= 'I') && (buffer[i] <= 'X'))
word = (word << 4) | (buffer[i] - 'I');
else {
switch (buffer[i]) {
case ('0'):
word = (word << 1) | 0;
break;
case ('1'):
word = (word << 1) | 1;
break;
default:
fprintf(stderr,
"WARNING - unexpected character (0x%02x) returned (in recv)\n",
buffer[i]);
} // switch
} // if ... else
} // for loop
if (DBG1) {
unsigned L4 = word >> 48;
unsigned L3 = (word >> 32) & 0xFFFF;
unsigned L2 = (word >> 16) & 0xFFFF;
unsigned L1 = word & 0xFFFF;
printf("TDO = %04x %04x %04x %04x (%i bits) <%s>\n",
L4, L3, L2, L1, a->BitsToRead, buffer);
}
a->TotalBitsReceived += a->BitsToRead;
a->BitsToRead = 0;
return word;
}
/*
* this routine performs the functions:
* (1) power up the target, then send out the ICSP signature to enable ICSP programming mode;
* (0) power down the target in an orderly fashion.
* (by RR)
*/
static void bitbang_ICSP_enable(bitbang_adapter_t *a, int ICSP_EN)
{
if (ICSP_EN)
{
// 50mS delay after powerup, pulse MCLR high, send signature, set MCLR high, 10mS delay
unsigned char buffer[64] = "5.88888.32.8.0100.1101.0100.0011.0100.1000.0101.0000.8.3.8......";
// 0000000001111111111222222222233333333334444444444555555555566666
// 1234567890123456789012345678901234567890123456789012345678901234
serial_write(buffer, 64);
usleep(150000); // 150mS delay to allow the above to percolate through the system
}
else
{
// 50mS delay then cut power
unsigned char buffer[16] = "88888.4.........";
// 0000000001111111
// 1234567890123456
serial_write(buffer, 16);
// 100mS delay to allow the above to percolate through the system
usleep(100000);
}
}
static void bitbang_close(adapter_t *adapter, int power_on)
{
bitbang_adapter_t *a = (bitbang_adapter_t*) adapter;
usleep(100000);
/* Clear EJTAGBOOT mode. */
bitbang_send(a, 1, 1, 5, TAP_SW_ETAP, 0); /* Send command. */
bitbang_send(a, 6, 31, 0, 0, 0); /* TMS 1-1-1-1-1-0 */
// (force the Chip TAP controller into Run Test/Idle state)
//
// not entirely sure the above sequence is correct.
// see pg 29 of microchip programming docs
//
bitbang_ICSP_enable(a, 0);
gettimeofday(&a->T2, 0);
printf("\n");
printf("total TDI/TMS pairs sent = %i pairs\n", a->TotalBitPairsSent);
printf("total TDO bits received = %i bits\n", a->TotalBitsReceived);
printf("total ascii codes sent = %i\n", a->TotalCodeChrsSent);
printf("total ascii codes recv = %i\n", a->TotalCodeChrsRecv);
printf("maximum continuous write = %i chars\n", a->MaxBufferedWrites);
printf("O/S serial writes = %i\n", a->WriteCount);
printf("O/S serial reads (data) = %i\n", a->Read1Count);
printf("O/S serial reads (sync) = %i\n", a->Read2Count);
printf("XferFastData count = %i\n", a->FDataCount);
printf("10mS delays (E/X/R) = %i/%i/%i\n", a->DelayCount[0],
a->DelayCount[1],
a->DelayCount[2]);
printf("elapsed programming time = %lum %02lus\n", (a->T2.tv_sec - a->T1.tv_sec) / 60,
(a->T2.tv_sec - a->T1.tv_sec) % 60);
serial_close(); // at this point we are exiting application???
// free(a); // suspect this line was causing XP CRASHES
// - shouldn't be needed anyway
}
/*
* Read the Device Identification code
*/
static unsigned bitbang_get_idcode(adapter_t *adapter)
{
bitbang_adapter_t *a = (bitbang_adapter_t*) adapter;
unsigned idcode;
if (DBG2)
fprintf(stderr, "get_idcode\n");
/* Reset the JTAG TAP controller: TMS 1-1-1-1-1-0.
* After reset, the IDCODE register is always selected.
* Read out 32 bits of data. */
bitbang_send(a, 6, 31, 32, 0, 1);
idcode = bitbang_recv(a);
return idcode;
}
/*
* Put device in serial execution mode. This is an alternative version
* taken directly from the microchip application note. The original
* version threw up a status error and then did an exit(-1), but
* when the exit was commented out still seemed to function.
* SEE: "PIC32 Flash Programming Specification 60001145N.pdf"
* (by RR)
*/
static void serial_execution(bitbang_adapter_t *a)
{
if (DBG2)
fprintf(stderr, "serial_execution\n");
if (a->serial_execution_mode)
return;
a->serial_execution_mode = 1;
/* Enter serial execution. */
if (debug_level > 0)
fprintf(stderr, "enter serial execution\n");
bitbang_send(a, 1, 1, 5, TAP_SW_MTAP, 0); /* Send command. */ // 1.
bitbang_send(a, 1, 1, 5, MTAP_COMMAND, 0); /* Send command. */ // 2.
bitbang_send(a, 0, 0, 8, MCHP_STATUS, 1); /* Xfer data. */ // 3.
unsigned status = bitbang_recv(a);
if (debug_level > 0)
fprintf(stderr, "status %04x\n", status);
if ((status & MCHP_STATUS_CPS) == 0) {
fprintf(stderr, "invalid status = %04x (code protection)\n", status); // 4.
exit(-1);
}
bitbang_send(a, 0, 0, 8, MCHP_ASSERT_RST, 0); /* Xfer data. */ // 5.
bitbang_send(a, 1, 1, 5, TAP_SW_ETAP, 0); /* Send command. */ // 6.
bitbang_send(a, 1, 1, 5, ETAP_EJTAGBOOT, 0); /* Send command. */ // 7.
bitbang_send(a, 1, 1, 5, TAP_SW_MTAP, 0); /* Send command. */ // 8.
bitbang_send(a, 1, 1, 5, MTAP_COMMAND, 0); /* Send command. */ // 9.
bitbang_send(a, 0, 0, 8, MCHP_DEASSERT_RST, 0); /* Xfer data. */ // 10.
if (memcmp(a->adapter.family_name, "mz", 2) != 0) // not needed for MZ processors
bitbang_send(a, 0, 0, 8, MCHP_FLASH_ENABLE, 0); /* Xfer data. */ // 11.
bitbang_send(a, 1, 1, 5, TAP_SW_ETAP, 0); /* Send command. */ // 12.
}
//
// Shouldn't XferFastData check the value of PrAcc returned in
// the LSB? We don't seem to be even reading this back.
// UPDATE1: The check is not needed in 4-wire JTAG mode, seems
// to only be required if in 2-wire ICSP mode. It would also
// slow us down horribly.
// UPDATE2: We are operating at such a slow speed that the PrAcc
// check is not really needed. To date, have never seen PrAcc != 1
//
static void xfer_fastdata(bitbang_adapter_t *a, unsigned word)
{
a->FDataCount++;
if (CFG2 == 1)
bitbang_send(a, 0, 0, 33, (unsigned long long) word << 1, 0);
if (CFG2 == 2) {
bitbang_send(a, 0, 0, 33, (unsigned long long) word << 1, 2);
unsigned status = bitbang_recv(a);
if (! (status & 1)) {
printf("!");
fflush(stdout);
}
}
//
// could add in code above to handle retrying if PrAcc == 0
//
// a better (faster) approach may be to 'accumulate' PrAcc at the
// programming adaptor, and then check the value at the end of a series
// of xfer_fastdata calls. we would need to implement an extra ascii
// command to use instead of 'D' (0x44) in the TDI header; '+' could be
// used as the check command (PrAcc |= TDO), while '=' used to read out
// the result (PrAcc) and reset the accumulator (PrAcc = 1) at the
// programming adaptor.
}
static void xfer_instruction(bitbang_adapter_t *a, unsigned instruction)
{
unsigned ctl;
if (debug_level > 1)
fprintf(stderr, "xfer instruction %08x\n", instruction);
// Select Control Register
bitbang_send(a, 1, 1, 5, ETAP_CONTROL, 0); /* Send command. */
// Wait until CPU is ready
// Check if Processor Access bit (bit 18) is set
int i = 0;
do {
if (i > 100)
bitbang_delay10mS(a, 1);
bitbang_send(a, 0, 0, 32, CONTROL_PRACC | /* Xfer data. */
CONTROL_PROBEN |
CONTROL_PROBTRAP |
/* CONTROL_EJTAGBRK */ 0, 1); // this bit should NOT be set
// Microchip document 60001145N, "PIC32 Flash Programming
// Specification, DS60001145N page 18 stipulates 0x0004C000:
// CONTROL_PRACC | CONTROL_PROBEN | CONTROL_PROBTRAP
ctl = bitbang_recv(a);
i++;
} while (! (ctl & CONTROL_PRACC) && i < 150);
if (i == 150) {
fprintf(stderr, "PE response, PrAcc not set (in XferInstruction)\n");
exit(-1);
}
// Select Data Register
// Send the instruction
bitbang_send(a, 1, 1, 5, ETAP_DATA, 0); /* Send command. */
bitbang_send(a, 0, 0, 32, instruction, 0); /* Send data. */
// Tell CPU to execute instruction
bitbang_send(a, 1, 1, 5, ETAP_CONTROL, 0); /* Send command. */
bitbang_send(a, 0, 0, 32, CONTROL_PROBEN | /* Send data. */
CONTROL_PROBTRAP, 0);
}
static unsigned get_pe_response(bitbang_adapter_t *a)
{
unsigned ctl, response;
// Select Control Register
bitbang_send(a, 1, 1, 5, ETAP_CONTROL, 0); /* Send command. */
// Wait until CPU is ready
// Check if Processor Access bit (bit 18) is set
int i = 0;
do {
if (i > 100)
bitbang_delay10mS(a, 2);
bitbang_send(a, 0, 0, 32, CONTROL_PRACC | /* Xfer data. */
CONTROL_PROBEN |
CONTROL_PROBTRAP |
/* CONTROL_EJTAGBRK */ 0, 1); // this bit should NOT be set
// Microchip document 60001145N, "PIC32 Flash Programming
// Specification, DS60001145N page 30 stipulates 0x0004C000:
// CONTROL_PRACC | CONTROL_PROBEN | CONTROL_PROBTRAP
ctl = bitbang_recv(a);
i++;
} while (! (ctl & CONTROL_PRACC) && i < 150);
if (i == 150) {
fprintf(stderr, "PE response, PrAcc not set (in GetPEResponse)\n");
exit(-1);
}
// Select Data Register
// Send the instruction
bitbang_send(a, 1, 1, 5, ETAP_DATA, 0); /* Send command. */
bitbang_send(a, 0, 0, 32, 0, 1); /* Get data. */
response = bitbang_recv(a);
// Tell CPU to execute NOP instruction
bitbang_send(a, 1, 1, 5, ETAP_CONTROL, 0); /* Send command. */
bitbang_send(a, 0, 0, 32, CONTROL_PROBEN | /* Send data. */
CONTROL_PROBTRAP, 0);
if (debug_level > 1)
fprintf(stderr, "get PE response %08x\n", response);
return response;
}
/*
* Read a word from memory (without PE).
*
* Only used to read configuration words.
*/
static unsigned bitbang_read_word(adapter_t *adapter, unsigned addr)
{
bitbang_adapter_t *a = (bitbang_adapter_t*) adapter;
unsigned addr_lo = addr & 0xFFFF;
unsigned addr_hi = (addr >> 16) & 0xFFFF;
if (DBG2)
fprintf(stderr, "read_word\n");
serial_execution(a);
xfer_instruction(a, 0x3c04bf80); // lui s3, 0xFF20
xfer_instruction(a, 0x3c080000 | addr_hi); // lui t0, addr_hi
xfer_instruction(a, 0x35080000 | addr_lo); // ori t0, addr_lo
xfer_instruction(a, 0x8d090000); // lw t1, 0(t0)
xfer_instruction(a, 0xae690000); // sw t1, 0(s3)
bitbang_send(a, 1, 1, 5, ETAP_FASTDATA, 0); /* Send command. */
bitbang_send(a, 0, 0, 33, 0, 1); /* Get fastdata. */
unsigned word = bitbang_recv(a) >> 1;
if (debug_level > 0)
fprintf(stderr, "read word at %08x -> %08x\n", addr, word);
return word;
}
/*
* Read a memory block.
*/
static void bitbang_read_data(adapter_t *adapter,
unsigned addr, unsigned nwords, unsigned *data)
{
bitbang_adapter_t *a = (bitbang_adapter_t*) adapter;
unsigned words_read, i;
if (DBG2)
fprintf(stderr, "read_data\n");
if (! a->use_executive) {
/* Without PE. */
for (i = nwords; i > 0; i--) {
*data++ = bitbang_read_word(adapter, addr);
addr += 4;
}
return;
}
/* Use PE to read memory. */
for (words_read = 0; words_read < nwords; words_read += 32) {
bitbang_send(a, 1, 1, 5, ETAP_FASTDATA, 0);
xfer_fastdata(a, PE_READ << 16 | 32); /* Read 32 words */
xfer_fastdata(a, addr); /* Address */
unsigned response = get_pe_response(a); /* Get response */
if (response != PE_READ << 16) {
fprintf(stderr, "bad READ response = %08x, expected %08x\n",
response, PE_READ << 16);
exit(-1);
}
for (i = 0; i < 32; i++) {
*data++ = get_pe_response(a); /* Get data */
}
addr += 32 * 4;
}
}
/*
* Download programming executive (PE).
*/
static void bitbang_load_executive(adapter_t *adapter,
const unsigned *pe, unsigned nwords, unsigned pe_version)
{
bitbang_adapter_t *a = (bitbang_adapter_t*) adapter;
a->use_executive = 1;
serial_execution(a);
printf(" Loading PE: ");
fflush(stdout);
if (memcmp(a->adapter.family_name, "mz", 2) != 0) { // steps 1. to 3. not needed for MZ
/* Step 1. */
xfer_instruction(a, 0x3c04bf88); // lui a0, 0xbf88
xfer_instruction(a, 0x34842000); // ori a0, 0x2000 - address of BMXCON
xfer_instruction(a, 0x3c05001f); // lui a1, 0x1f
xfer_instruction(a, 0x34a50040); // ori a1, 0x40 - a1 has 001f0040
xfer_instruction(a, 0xac850000); // sw a1, 0(a0) - BMXCON initialized
printf("1");
fflush(stdout);
/* Step 2. */
xfer_instruction(a, 0x34050800); // li a1, 0x800 - a1 has 00000800
xfer_instruction(a, 0xac850010); // sw a1, 16(a0) - BMXDKPBA initialized
printf(" 2");
fflush(stdout);
/* Step 3. */
xfer_instruction(a, 0x8c850040); // lw a1, 64(a0) - load BMXDMSZ
xfer_instruction(a, 0xac850020); // sw a1, 32(a0) - BMXDUDBA initialized
xfer_instruction(a, 0xac850030); // sw a1, 48(a0) - BMXDUPBA initialized
printf(" 3");
fflush(stdout);
}
/* Step 4. */
xfer_instruction(a, 0x3c04a000); // lui a0, 0xa000
xfer_instruction(a, 0x34840800); // ori a0, 0x800 - a0 has a0000800
printf(" 4 (LDR)");
fflush(stdout);
/* Download the PE loader. */
int i;
for (i = 0; i < PIC32_PE_LOADER_LEN; i += 2) {
/* Step 5. */
unsigned opcode1 = 0x3c060000 | pic32_pe_loader[i];
unsigned opcode2 = 0x34c60000 | pic32_pe_loader[i+1];
xfer_instruction(a, opcode1); // lui a2, PE_loader_hi++
xfer_instruction(a, opcode2); // ori a2, PE_loader_lo++
xfer_instruction(a, 0xac860000); // sw a2, 0(a0)
xfer_instruction(a, 0x24840004); // addiu a0, 4
}
printf(" 5");
fflush(stdout);
/* Jump to PE loader (step 6). */
xfer_instruction(a, 0x3c19a000); // lui t9, 0xa000
xfer_instruction(a, 0x37390800); // ori t9, 0x800 - t9 has a0000800
xfer_instruction(a, 0x03200008); // jr t9
xfer_instruction(a, 0x00000000); // nop
printf(" 6");
fflush(stdout);
/* Switch from serial to fast execution mode. */
//bitbang_send(a, 1, 1, 5, TAP_SW_ETAP, 0);
//bitbang_send(a, 6, 31, 0, 0, 0); /* TMS 1-1-1-1-1-0 */
//
// the above two lines are not present in the Microchip programming specs
//
/* Send parameters for the loader (step 7-A).
* PE_ADDRESS = 0xA000_0900,
* PE_SIZE */
bitbang_send(a, 1, 1, 5, ETAP_FASTDATA, 0); /* Send command. */
xfer_fastdata(a, 0xa0000900);
xfer_fastdata(a, nwords);
printf(" 7a (PE)");
fflush(stdout);
/* Download the PE itself (step 7-B). */
for (i = 0; i < nwords; i++) {
xfer_fastdata(a, *pe++);
}
bitbang_delay10mS(a, 3);
printf(" 7b");
fflush(stdout);
/* Download the PE instructions. */
xfer_fastdata(a, 0); /* Step 8 - jump to PE. */
xfer_fastdata(a, 0xDEAD0000);
bitbang_delay10mS(a, 3);
printf(" 8");
fflush(stdout);
xfer_fastdata(a, PE_EXEC_VERSION << 16);
unsigned version = get_pe_response(a);
if (version != (PE_EXEC_VERSION << 16 | pe_version)) {
fprintf(stderr, "\nbad PE version = %08x, expected %08x\n",
version, PE_EXEC_VERSION << 16 | pe_version);
exit(-1);
}
printf(" v%04x\n", version & 0xFFFF);
if (debug_level > 0)
fprintf(stderr, "PE version = %04x\n", version & 0xffff);
}
/*
* Erase all flash memory.
*/
static void bitbang_erase_chip(adapter_t *adapter)
{
bitbang_adapter_t *a = (bitbang_adapter_t*) adapter;
if (DBG2)
fprintf(stderr, "erase_chip\n");
bitbang_send(a, 1, 1, 5, TAP_SW_MTAP, 0); /* Send command. */
bitbang_send(a, 1, 1, 5, MTAP_COMMAND, 0); /* Send command. */
bitbang_send(a, 0, 0, 8, MCHP_ERASE, 0); /* Xfer data. */
if (memcmp(a->adapter.family_name, "mz", 2) == 0)
bitbang_send(a, 0, 0, 8, MCHP_DEASSERT_RST, 0); // needed for PIC32MZ devices only.
int i = 0;
unsigned status;
do {
bitbang_delay10mS(a, 0);
bitbang_send(a, 0, 0, 8, MCHP_STATUS, 1); /* Xfer data. */
status = bitbang_recv(a);
i++;
} while ((status & (MCHP_STATUS_CFGRDY |
MCHP_STATUS_FCBUSY)) != MCHP_STATUS_CFGRDY && i < 100);
if (i == 100) {
fprintf(stderr, "invalid status = %04x (in erase chip)\n", status);
exit(-1);
}
printf("(%imS) ", i * 10);
fflush(stdout);
}
/*
* Write a word to flash memory. (only seems to be used to write the four configuration words)
*
* !!!!!!!!!! WARNING !!!!!!!!!!
* on PIC32MZ EC family devices PE_WORD_PROGRAM will not generate the ECC parity bits;
* instead should use QUAD_WORD_PGRM to program all four configuration words at once.
* !!!!!!!!!! WARNING !!!!!!!!!!
*/
static void bitbang_program_word(adapter_t *adapter,
unsigned addr, unsigned word)
{
bitbang_adapter_t *a = (bitbang_adapter_t*) adapter;
if (DBG2)
fprintf(stderr, "program_word\n");
if (debug_level > 0)
fprintf(stderr, "program word at %08x: %08x\n", addr, word);
if (! a->use_executive) {
/* Without PE. */
fprintf(stderr, "slow flash write not implemented yet\n");
exit(-1);
}
if (memcmp(a->adapter.family_name, "mz", 2) == 0) {
printf("!ECC!"); // warn if word-write to MZ processor
fflush(stdout);
}
/* Use PE to write flash memory. */
bitbang_send(a, 1, 1, 5, ETAP_FASTDATA, 0); /* Send command. */
xfer_fastdata(a, PE_WORD_PROGRAM << 16 | 2);
xfer_fastdata(a, addr); /* Send address. */
xfer_fastdata(a, word); /* Send word. */
unsigned response = get_pe_response(a);
if (response != (PE_WORD_PROGRAM << 16)) {
fprintf(stderr, "\nfailed to program word %08x at %08x, reply = %08x\n",
word, addr, response);
exit(-1);
}
}
/*
* Flash write row of memory.
*/
static void bitbang_program_row(adapter_t *adapter, unsigned addr,
unsigned *data, unsigned words_per_row)
{
bitbang_adapter_t *a = (bitbang_adapter_t*) adapter;
if (DBG2)
fprintf(stderr, "program_row\n");
if (DBG3)
fprintf(stderr, "\nprogramming %u words at %08x ",
words_per_row, addr);
if (debug_level > 0)
fprintf(stderr, "row program %u words at %08x\n", words_per_row, addr);
if (! a->use_executive) {
/* Without PE. */
fprintf(stderr, "slow flash write not implemented yet\n");
exit(-1);
}
/* Use PE to write flash memory. */
bitbang_send(a, 1, 1, 5, ETAP_FASTDATA, 0); /* Send command. */
xfer_fastdata(a, PE_ROW_PROGRAM << 16 | words_per_row);
xfer_fastdata(a, addr); /* Send address. */
//
// The below for loop seems to be where our biggest programming time bottleneck is.
//
/* Download data. */
int i;
for (i = 0; i < words_per_row; i++) {
xfer_fastdata(a, *data++); /* Send word. */
}
unsigned response = get_pe_response(a);
if (response != (PE_ROW_PROGRAM << 16)) {
fprintf(stderr, "\nfailed to program row at %08x, reply = %08x\n",
addr, response);
exit(-1);
}
}
/*
* Verify a block of memory.
*/
static void bitbang_verify_data(adapter_t *adapter,
unsigned addr, unsigned nwords, unsigned *data)
{
bitbang_adapter_t *a = (bitbang_adapter_t*) adapter;
unsigned data_crc, flash_crc;
if (DBG2)
fprintf(stderr, "verify_data\n");
if (DBG3)
fprintf(stderr, "\nverifying %u words at %08x ", nwords, addr);
if (! a->use_executive) {
/* Without PE. */
fprintf(stderr, "slow verify not implemented yet\n");
exit(-1);
}
/* Use PE to get CRC of flash memory. */
bitbang_send(a, 1, 1, 5, ETAP_FASTDATA, 0); /* Send command. */
xfer_fastdata(a, PE_GET_CRC << 16);
xfer_fastdata(a, addr); /* Send address. */
xfer_fastdata(a, nwords * 4); /* Send length. */
unsigned response = get_pe_response(a);
if (response != (PE_GET_CRC << 16)) {
fprintf(stderr, "\nfailed to verify %d words at %08x, reply = %08x\n",
nwords, addr, response);
exit(-1);
}
flash_crc = get_pe_response(a) & 0xffff;
data_crc = calculate_crc(0xffff, (unsigned char*) data, nwords * 4);
if (flash_crc != data_crc) {
fprintf(stderr, "\nchecksum failed at %08x: returned %04x, expected %04x\n",
addr, flash_crc, data_crc);
exit(-1);
}
}
/*
* Initialize bitbang adapter.
* Return a pointer to a data structure, allocated dynamically.