1 /*
2 * Copyright (C) 2005-2019 Darron Broad
3 * All rights reserved.
4 *
5 * This file is part of Pickle Microchip PIC ICSP.
6 *
7 * Pickle Microchip PIC ICSP is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation.
10 *
11 * Pickle Microchip PIC ICSP is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 * Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with Pickle Microchip PIC ICSP. If not, see http://www.gnu.org/licenses/
18 */
19
20 #include "pickle.h"
21
22 /******************************************************************************
23 *
24 * Session
25 *
26 *****************************************************************************/
27
28 extern struct pickle p;
29
30 /*****************************************************************************
31 *
32 * Hardware operations
33 *
34 *****************************************************************************/
35
36 struct pic_ops pic12_ops = {
37 .arch = ARCH12BIT,
38 .align = sizeof(uint16_t),
39 .selector = pic12_selector,
40 .bootloader = NULL,
41 .program_begin = NULL,
42 .program_data = pic12_program_data,
43 .program_end = pic12_program_end,
44 .verify_begin = NULL,
45 .verify_data = pic12_verify_data,
46 .verify_end = pic12_standby,
47 .view_data = pic12_view_data,
48 .read_config_memory = pic12_read_config_memory,
49 .get_program_count = pic12_get_program_count,
50 .get_program_size = pic12_get_program_size,
51 .get_data_size = pic12_get_data_size,
52 .get_executive_size = NULL,
53 .get_boot_size = NULL,
54 .read_program_memory_block = pic12_read_program_memory_block,
55 .read_data_memory_block = pic12_read_data_memory_block,
56 .write_panel = NULL,
57 .bulk_erase = pic12_bulk_erase,
58 .write_osccal = pic12_write_osccal,
59 .write_bandgap = NULL,
60 .write_calib = NULL,
61 .row_erase = NULL,
62 .dumpdeviceid = pic12_dumpdeviceid,
63 .dumpconfig = pic12_dumpconfig,
64 .dumposccal = pic12_dumposccal,
65 .dumpdevice = pic12_dumpdevice,
66 .dumpadj = 1,
67 .dumphexcode = pic12_dumphexcode,
68 .dumpinhxcode = pic12_dumpinhxcode,
69 .dumphexdata = pic12_dumphexdata,
70 .dumpinhxdata = pic12_dumpinhxdata,
71 .debug = NULL,
72 };
73
74 uint32_t
pic12_arch(void)75 pic12_arch(void)
76 {
77 p.pic = &pic12_ops;
78
79 return p.pic->arch;
80 }
81
82 /*****************************************************************************
83 *
84 * Hardware configuration
85 *
86 *****************************************************************************/
87
88 struct pic12_config pic12_conf;
89
90 /*****************************************************************************
91 *
92 * Hardware algorithm map
93 *
94 *****************************************************************************/
95
96 struct pic12_dsmap pic12_map[] =
97 {
98 /*Device name Device id Flash Data Data-sheet Backup OSC Config #Latches*/
99 {"PIC12F508", PIC12F508, 512, 0, DS41227E, 0x0204, 0x03FF, 1},
100 {"PIC12F509", PIC12F509, 1024, 0, DS41227E, 0x0404, 0x07FF, 1},
101
102 {"PIC16F505", PIC16F505, 1024, 0, DS41226G, 0x0404, 0x07FF, 1},
103
104 {"PIC12F510", PIC12F510, 1024, 0, DS41257B, 0x0404, 0x07FF, 1},
105
106 {"PIC16F506", PIC16F506, 1024, 0, DS41258C, 0x0404, 0x07FF, 1},
107
108 {"PIC10F200", PIC10F200, 256, 0, DS41228F, 0x0104, 0x01FF, 1},
109 {"PIC10F202", PIC10F202, 512, 0, DS41228F, 0x0204, 0x03FF, 1},
110 {"PIC10F204", PIC10F204, 256, 0, DS41228F, 0x0104, 0x01FF, 1},
111 {"PIC10F206", PIC10F206, 512, 0, DS41228F, 0x0204, 0x03FF, 1},
112
113 {"PIC16F54", PIC16F54, 512, 0, DS41207D, 0, 0x03FF, 1},
114
115 {"PIC16F57", PIC16F57, 2048, 0, DS41208C, 0, 0x0FFF, 4},
116
117 {"PIC16F59", PIC16F59, 2048, 0, DS41243B, 0, 0x0FFF, 4},
118
119 {"PIC10F220", PIC10F220, 256, 0, DS41266C, 0x0104, 0x01FF, 1},
120 {"PIC10F222", PIC10F222, 512, 0, DS41266C, 0x0204, 0x03FF, 1},
121
122 {"PIC12F519", PIC12F519, 1024, +64, DS41316C, 0x0444, 0x07FF, 1},
123
124 {"PIC16F570", PIC16F570, 2048, +64, DS41670A, 0x0844, 0x0FFF, 4},
125
126 {"PIC16F527", PIC16F527, 1024, +64, DS41640A, 0x0444, 0x07FF, 1},
127
128 {"PIC16F526", PIC16F526, 1024, +64, DS41317B, 0x0444, 0x07FF, 1},
129
130 {"(null)", 0, 0, 0, 0, 0, 0, 0}
131 /*Device name Device id Flash Data Data-sheet Backup OSC Config #Latches*/
132 };
133 #define PIC12_SIZE ((sizeof(pic12_map) / sizeof(struct pic12_dsmap)) - 1)
134
135 /* Default device (null) */
136 uint32_t pic12_index = PIC12_SIZE;
137
138 void
pic12_selector(void)139 pic12_selector(void)
140 {
141 uint32_t i;
142 char *dnames[PIC12_SIZE];
143
144 for (i = 0; i < PIC12_SIZE; ++i) {
145 dnames[i] = pic12_map[i].devicename;
146 }
147 qsort(dnames, PIC12_SIZE, sizeof(char *), pic_cmp);
148 for (i = 0; i < PIC12_SIZE; ++i) {
149 if ((i % PIC_NCOLS) == (PIC_NCOLS - 1))
150 printf("%s\n", dnames[i]);
151 else
152 printf("%s\t", dnames[i]);
153 }
154 if (i % PIC_NCOLS)
155 printf("\n");
156 printf("Total: %d\n", (uint32_t)PIC12_SIZE);
157 }
158
159 /*****************************************************************************
160 *
161 * Program/Verify mode
162 *
163 *****************************************************************************/
164
165 /*
166 * ENTER HVP PROGRAM/VERIFY MODE
167 *
168 * ENTRY - VDD FIRST
169 *
170 * DS41226G-page 4 PIC16F505
171 * DS41228F-page 4 PIC10F200
172 * DS41207D-page 3 PIC16F54
173 * DS41670A-page 5 PIC16F570
174 */
175 void
pic12_program_verify(void)176 pic12_program_verify(void)
177 {
178 /* RESET & ACQUIRE GPIO */
179 io_set_vpp(LOW);
180 /* DS41226G PIC16F505 TPPDP(5us) */
181 /* DS41228F PIC10F200 TPPDP(5us) */
182 /* DS41207D PIC16F54 TPPDP(5us) */
183 /* DS41670A PIC16F570 TPPDP(5us) */
184 io_usleep(1000);
185
186 /* PGD + PGC + PGM(N/A) LOW */
187 io_set_pgd(LOW);
188 io_set_pgc(LOW);
189 io_set_pgm(LOW);
190 io_usleep(1000);
191
192 /* INPUT DATA ON CLOCK RISING EDGE, LSB FIRST */
193 io_configure(FALSE, FALSE);
194
195 /* VPP HIGH */
196 io_set_vpp(HIGH);
197 /* DS41226G PIC16F505 THLD0(5us) */
198 /* DS41228F PIC10F200 THLD0(5us) */
199 /* DS41207D PIC16F54 THLD0(5us) */
200 /* DS41670A PIC16F570 THLD0(5us) */
201 io_usleep(250);
202 }
203
204 /*
205 * EXIT HVP PROGRAM/VERIFY MODE
206 *
207 * EXIT - VDD LAST
208 *
209 * DS41228F-page 5 PIC10F200
210 */
211 void
pic12_standby(void)212 pic12_standby(void)
213 {
214 /* PGD + PGC + VPP + PGM(N/A) LOW */
215 io_set_pgd(LOW);
216 io_set_pgc(LOW);
217 io_set_vpp(LOW);
218 io_set_pgm(LOW);
219 }
220
221 /*****************************************************************************
222 *
223 * Hardware functions
224 *
225 *****************************************************************************/
226
227 /*I/O*************************************************************************/
228
229 /*
230 * LOAD DATA FOR PROGRAM MEMORY
231 * PC <= 0x07FF (PIC16F505)
232 * WR <= word
233 *
234 * XX0010 = 0x02
235 *
236 * DS41226G-page 4 16F505
237 * DS41227E-page 3 12F508
238 * DS41258C-page 4 16F506
239 * DS41228F-page 6 10F200
240 * DS41207D-page 3 16F54
241 * DS41266C-page 3 10F220
242 * DS41316C-page 3 12F519
243 * DS41670A-page 5 16F570
244 */
245 static inline void
pic12_load_data_for_program_memory(uint16_t word)246 pic12_load_data_for_program_memory(uint16_t word)
247 {
248 io_program_out(0x02, 6);
249 word = (word << 1) | 0x8001;
250 io_program_out(word, 16);
251 }
252
253 /*
254 * READ DATA FROM PROGRAM MEMORY
255 * RETURN (PC)
256 *
257 * XX0100 = 0x04
258 *
259 * DS41226G-page 4 16F505
260 * DS41227E-page 3 12F508
261 * DS41258C-page 4 16F506
262 * DS41228F-page 6 10F200
263 * DS41207D-page 3 16F54
264 * DS41266C-page 3 10F220
265 * DS41316C-page 3 12F519
266 * DS41670A-page 5 16F570
267 */
268 static inline uint16_t
pic12_read_data_from_program_memory(void)269 pic12_read_data_from_program_memory(void)
270 {
271 uint16_t word;
272
273 io_program_out(0x04, 6);
274 word = io_program_in(16);
275 word = (word >> 1) & PIC12_MASK;
276
277 return word;
278 }
279
280 /*
281 * INCREMENT ADDRESS
282 * PC <= 1 + PC
283 *
284 * XX0110 = 0x06
285 *
286 * DS41226G-page 4 16F505
287 * DS41227E-page 3 12F508
288 * DS41258C-page 4 16F506
289 * DS41228F-page 6 10F200
290 * DS41207D-page 3 16F54
291 * DS41266C-page 3 10F220
292 * DS41316C-page 3 12F519
293 * DS41670A-page 5 16F570
294 */
295 static inline void
pic12_increment_address(void)296 pic12_increment_address(void)
297 {
298 io_program_out(0x06, 6);
299 }
300
301 /*PROG************************************************************************/
302
303 /*
304 * BEGIN PROGRAMMING
305 * (PC) <= WR
306 *
307 * XX1000 = 0x08
308 *
309 * DS41226G-page 4 16F505 TPROG(2ms)
310 * DS41227E-page 3 12F508 TPROG(2ms)
311 * DS41258C-page 4 16F506 TPROG(2ms)
312 * DS41228F-page 6 10F200 TPROG(2ms)
313 * DS41207D-page 3 16F54 TPROG(2ms)
314 * DS41208C-page 3 16F57 TPROG(2ms)
315 * DS41266C-page 3 10F220 TPROG(2ms)
316 * DS41316C-page 3 12F519 TPROG(2ms)
317 * DS41670A-page 5 16F570 TPROG(2ms)
318 */
319 static inline void
pic12_begin_programming(void)320 pic12_begin_programming(void)
321 {
322 io_program_out(0x08, 6);
323 io_usleep(PIC12_TPROG_DEFAULT);
324 }
325
326 /*
327 * END PROGRAMMING
328 *
329 * XX1110 = 0x0E
330 *
331 * DS41226G-page 4 16F505 TDIS(100us)
332 * DS41227E-page 3 12F508 TDIS(100us)
333 * DS41258C-page 4 16F506 TDIS(100us)
334 * DS41228F-page 6 10F200 TDIS(100us)
335 * DS41207D-page 3 16F54 TDIS(100us)
336 * DS41208C-page 3 16F57 TDIS(100us)
337 * DS41266C-page 3 10F220 TDIS(100us)
338 * DS41316C-page 3 12F519 TDIS(100us)
339 * DS41670A-page 5 16F570 TDIS(300us)
340 */
341 static inline void
pic12_end_programming(void)342 pic12_end_programming(void)
343 {
344 uint32_t tdis = PIC12_TDISCHARGE_DEFAULT;
345
346 if (pic12_map[pic12_index].datasheet == DS41670A) /* PIC16F570 */
347 tdis = PIC12_TDISCHARGE_300US;
348
349 io_program_out(0x0E, 6);
350 io_usleep(tdis);
351 }
352
353 /*ERASE***********************************************************************/
354
355 /*
356 * BULK ERASE PROGRAM MEMORY
357 *
358 * XX1001 = 0x09
359 *
360 * DS41226G-page 4 16F505 TERA(10ms)
361 * DS41227E-page 3 12F508 TERA(10ms)
362 * DS41258C-page 4 16F506 TERA(10ms)
363 * DS41228F-page 6 10F200 TERA(10ms)
364 * DS41207D-page 3 16F54 TERA(10ms)
365 * DS41208C-page 3 16F57 TERA(10ms)
366 * DS41266C-page 3 10F220 TERA(10ms)
367 * DS41316C-page 3 12F519 TERA(10ms)
368 * DS41670A-page 5 16F570 TERA(10ms)
369 */
370 static inline void
pic12_bulk_erase_program_memory(void)371 pic12_bulk_erase_program_memory(void)
372 {
373 io_program_out(0x09, 6);
374 io_usleep(PIC12_TERASE_DEFAULT);
375 }
376
377 /*****************************************************************************
378 *
379 * Compound functions
380 *
381 *****************************************************************************/
382
383 /*
384 * READ PROGRAM MEMORY
385 *
386 * RETURN CODE WORD, INCREMENT PC
387 */
388 uint16_t
pic12_read_program_memory_increment(void)389 pic12_read_program_memory_increment(void)
390 {
391 uint16_t data = pic12_read_data_from_program_memory();
392
393 pic12_increment_address();
394
395 return data;
396 }
397
398 /*
399 * ERASE DEVICE
400 */
401 void
pic12_erase_device(void)402 pic12_erase_device(void)
403 {
404 uint32_t i;
405
406 pic12_program_verify();
407
408 if (pic12_map[pic12_index].dataflash == 0) {
409 pic12_increment_address(); /* Skip config word */
410
411 for (i = 0; i < pic12_map[pic12_index].flash; i++)
412 pic12_increment_address(); /* Skip program flash */
413
414 pic12_bulk_erase_program_memory(); /* Erase device */
415 } else {
416 /* PIC12F519 */
417 /* PIC16F570 */
418 /* PIC16F527 */
419 pic12_bulk_erase_program_memory(); /* Erase config & program flash */
420
421 pic12_increment_address(); /* Skip config word */
422
423 for (i = 0; i < pic12_map[pic12_index].flash; i++)
424 pic12_increment_address(); /* Skip program flash */
425
426 pic12_bulk_erase_program_memory(); /* Erase data flash */
427
428 for (i = 0; i < pic12_map[pic12_index].dataflash; i++)
429 pic12_increment_address(); /* Skip data flash */
430
431 pic12_bulk_erase_program_memory(); /* Erase user id & osccal */
432 }
433
434 pic12_standby();
435 }
436
437 /*
438 * BLANK DEVICE
439 *
440 * DISABLE PROTECTION AND BULK ERASE
441 */
442 void
pic12_bulk_erase(void)443 pic12_bulk_erase(void)
444 {
445 pic12_erase_device();
446
447 if (pic12_map[pic12_index].backupaddr) {
448 pic12_osccal_write(pic12_conf.osccal_backup);
449 }
450 }
451
452 /*****************************************************************************
453 *
454 * Read block data
455 *
456 *****************************************************************************/
457
458 /*
459 * READ CONFIGURATION MEMORY
460 *
461 * READ CONFIG WORD AND USERID
462 */
463 int
pic12_read_config_memory(void)464 pic12_read_config_memory(void)
465 {
466 uint32_t dev;
467
468 /* NULL device */
469 pic12_index = PIC12_SIZE;
470
471 /* Reset configuraton */
472 memset(&pic12_conf, 0, sizeof(pic12_conf));
473
474 /* Device detect not available */
475 if (!p.devicename[0]) {
476 printf("%s: information: device must be selected on this architecture\n", __func__);
477 return -1;
478 }
479
480 /* Device selected by user */
481 for (dev = 0; pic12_map[dev].deviceid; ++dev) {
482 if (strcasecmp(pic12_map[dev].devicename, p.devicename) == 0) {
483 break;
484 }
485 }
486 if (pic12_map[dev].deviceid == 0) {
487 printf("%s: information: unknown device: [%s]\n", __func__, p.devicename);
488 return -1;
489 }
490
491 pic12_program_verify();
492 pic12_conf.config = pic12_read_program_memory_increment();
493
494 /*
495 * VELLEMAN K8048 SWITCH IN STANDBY [0000]
496 * VELLEMAN K8048 NO POWER [3FFF]
497 * VELLEMAN K0848 SWITCH IN RUN [3FFF]
498 */
499 if (pic12_conf.config == 0x0000 || pic12_conf.config == 0x3FFF) {
500 printf("%s: information: %s\n", __func__, io_fault(pic12_conf.config));
501 pic12_standby();
502 return -1;
503 }
504
505 /* Device recognised */
506 pic12_index = dev;
507
508 /*
509 * Get OSCCAL / USERID / BACKUP OSCCAL
510 *
511 * Not all devices support OSCCAL but all support USERID
512 */
513
514 for (uint32_t i = 0; i < (pic12_map[pic12_index].flash - 1); ++i)
515 pic12_increment_address(); /* Skip program flash */
516
517 /* Get OSCCAL RESET */
518 pic12_conf.osccal_reset = pic12_read_program_memory_increment();
519 for (uint32_t i = 0; i < pic12_map[pic12_index].dataflash; ++i)
520 pic12_increment_address(); /* Skip data flash */
521
522 /* Get USERID 0..3 */
523 pic12_conf.userid[0] = pic12_read_program_memory_increment();
524 pic12_conf.userid[1] = pic12_read_program_memory_increment();
525 pic12_conf.userid[2] = pic12_read_program_memory_increment();
526 pic12_conf.userid[3] = pic12_read_program_memory_increment();
527
528 /* Get OSCCAL BACKUP */
529 pic12_conf.osccal_backup = pic12_read_program_memory_increment();
530
531 pic12_standby();
532
533 return 0;
534 }
535
536 /*
537 * GET PROGRAM COUNT
538 *
539 * RETURN NUMBER OF PARTITIONS
540 */
541 uint32_t
pic12_get_program_count(void)542 pic12_get_program_count(void)
543 {
544 return 1;
545 }
546
547 /*
548 * GET PROGRAM FLASH SIZE
549 *
550 * RETURN SIZE IN WORDS
551 */
552 uint32_t
pic12_get_program_size(uint32_t * addr,uint32_t partition)553 pic12_get_program_size(uint32_t *addr, uint32_t partition)
554 {
555 *addr = 0;
556
557 return pic12_map[pic12_index].flash;
558 }
559
560 /*
561 * GET DATA EEPROM/FLASH SIZE
562 *
563 * RETURN SIZE IN BYTES
564 */
565 uint32_t
pic12_get_data_size(uint32_t * addr)566 pic12_get_data_size(uint32_t *addr)
567 {
568 *addr = pic12_map[pic12_index].flash;
569
570 return pic12_map[pic12_index].dataflash;
571 }
572
573 /*
574 * READ PROGRAM FLASH MEMORY BLOCK ADDR .. ADDR + SIZE
575 *
576 * RETURN ADDR
577 */
578 uint32_t
pic12_read_program_memory_block(uint32_t * data,uint32_t addr,uint32_t size)579 pic12_read_program_memory_block(uint32_t *data, uint32_t addr, uint32_t size)
580 {
581 uint32_t i;
582
583 pic12_program_verify();
584 pic12_increment_address(); /* Skip config word */
585
586 for (i = 0; i < addr; ++i)
587 pic12_increment_address();
588 for (i = 0; i < size; ++i)
589 data[i] = (uint32_t)pic12_read_program_memory_increment();
590
591 pic12_standby();
592
593 return addr;
594 }
595
596 /*
597 * READ DATA EEPROM/FLASH MEMORY BLOCK ADDR .. ADDR + SIZE
598 *
599 * RETURN ADDR
600 */
601 uint32_t
pic12_read_data_memory_block(uint16_t * data,uint32_t addr,uint16_t size)602 pic12_read_data_memory_block(uint16_t *data, uint32_t addr, uint16_t size)
603 {
604 uint32_t i;
605
606 pic12_program_verify();
607 pic12_increment_address(); /* Skip config word */
608
609 for (i = 0; i < addr; ++i)
610 pic12_increment_address();
611 for (i = 0; i < size; ++i)
612 data[i] = (uint16_t)pic12_read_program_memory_increment();
613
614 pic12_standby();
615
616 return addr;
617 }
618
619 /*****************************************************************************
620 *
621 * Read/Write Calibration
622 *
623 *****************************************************************************/
624
625 /*
626 * WRITE OSCILLATOR CALIBRATION WORD
627 */
628 uint32_t
pic12_osccal_write(uint16_t osccal)629 pic12_osccal_write(uint16_t osccal)
630 {
631 uint32_t i;
632
633 pic12_program_verify();
634
635 pic12_increment_address(); /* Skip config word */
636 for (i = 0; i < (pic12_map[pic12_index].flash - 1); i++)
637 pic12_increment_address(); /* Skip program flash memory */
638
639 /*
640 * Write OSCCAL RESET
641 */
642 pic12_load_data_for_program_memory(osccal);
643 pic12_begin_programming();
644 pic12_end_programming();
645 uint16_t vdata = pic12_read_data_from_program_memory();
646 if (vdata != osccal) {
647 pic12_standby();
648 printf("%s: error: OSCCAL RESET write failed: read [%04X] expected [%04X]\n",
649 __func__, vdata, osccal);
650 return 0;
651 }
652 pic12_increment_address(); /* Skip OSCCAL RESET */
653
654 for (i = 0; i < pic12_map[pic12_index].dataflash; i++)
655 pic12_increment_address(); /* Skip data flash */
656
657 pic12_increment_address(); /* Skip USERID0 */
658 pic12_increment_address(); /* Skip USERID1 */
659 pic12_increment_address(); /* Skip USERID2 */
660 pic12_increment_address(); /* Skip USERID3 */
661
662 /*
663 * Write OSCCAL BACKUP
664 */
665 pic12_load_data_for_program_memory(osccal);
666 pic12_begin_programming();
667 pic12_end_programming();
668 vdata = pic12_read_data_from_program_memory();
669 if (vdata != osccal) {
670 pic12_standby();
671 printf("%s: error: OSCCAL BACKUP write failed: read [%04X] expected [%04X]\n",
672 __func__, vdata, osccal);
673 return 0;
674 }
675
676 pic12_standby();
677
678 return 1; /* OSCCAL WRITTEN */
679 }
680
681 /*****************************************************************************
682 *
683 * Write Calibration to Blank Device
684 *
685 *****************************************************************************/
686
687 /*
688 * WRITE OSCILLATOR CALIBRATION WORD
689 */
690 uint32_t
pic12_write_osccal(uint16_t osccal)691 pic12_write_osccal(uint16_t osccal)
692 {
693 if (pic12_map[pic12_index].backupaddr == 0) {
694 printf("%s: error: OSCCAL is not supported on this device\n", __func__);
695 return 0;
696 }
697
698 pic12_erase_device();
699
700 return pic12_osccal_write(osccal);
701 }
702
703 /*****************************************************************************
704 *
705 * Program Config
706 *
707 *****************************************************************************/
708
709 /*
710 * WRITE CONFIG
711 */
712 uint32_t
pic12_write_config(void)713 pic12_write_config(void)
714 {
715 pic12_program_verify();
716
717 /* Store config in working register */
718 pic12_load_data_for_program_memory(pic12_conf.config);
719
720 /* Program working register */
721 pic12_begin_programming();
722 pic12_end_programming();
723
724 pic12_standby();
725
726 return 1;
727 }
728
729 /*****************************************************************************
730 *
731 * Region control
732 *
733 *****************************************************************************/
734
735 /*
736 * DETERMINE MEMORY REGION: CODE (PROGRAM FLASH + DATA FLASH + USERID) OR CONFIG
737 *
738 * RETURN PIC_REGIONCODE:
739 * 0 .. FLASH SIZE
740 *
741 * RETURN PIC_REGIONCONFIG:
742 * 0xFFF
743 */
744 uint16_t
pic12_getregion(uint16_t address)745 pic12_getregion(uint16_t address)
746 {
747 /* CODE: PROGRAM FLASH/DATA FLASH/USERID */
748 uint16_t code_high = pic12_map[pic12_index].flash + pic12_map[pic12_index].dataflash + 3;
749
750 if (address <= code_high) {
751 return PIC_REGIONCODE;
752 }
753 /* CONFIG */
754 if (address == PIC12_CONFIG) {
755 return PIC_REGIONCONFIG;
756 }
757 if (p.f) fprintf(p.f, "%s: warning: address unsupported [%04X]\n",
758 __func__, address);
759 return PIC_REGIONNOTSUP;
760 }
761
762 /*
763 * INITIALISE FOR REGION
764 */
765 uint16_t
pic12_initregion(uint16_t region,uint16_t * address)766 pic12_initregion(uint16_t region, uint16_t *address)
767 {
768 switch (region) {
769 case PIC_REGIONCODE:
770 /* Skip config word */
771 pic12_increment_address();
772 *address = 0;
773 return region;
774 case PIC_REGIONCONFIG:
775 *address = PIC12_CONFIG;
776 return region;
777 }
778 if (p.f) fprintf(p.f, "%s: warning: region unsupported [%d]\n",
779 __func__, region);
780 *address = 0;
781 return PIC_REGIONNOTSUP;
782 }
783
784 /*
785 * LOAD DATA FOR REGION (STORE WORD IN WORKING REGISTER)
786 */
787 void
pic12_loadregion(uint16_t region,uint16_t word)788 pic12_loadregion(uint16_t region, uint16_t word)
789 {
790 switch (region) {
791 case PIC_REGIONCODE:
792 case PIC_REGIONCONFIG:
793 pic12_load_data_for_program_memory(word);
794 return;
795 }
796 if (p.f) fprintf(p.f, "%s: warning: region unsupported [%d]\n",
797 __func__, region);
798 }
799
800 /*****************************************************************************
801 *
802 * Program & verify region
803 *
804 *****************************************************************************/
805
806 /*
807 * PROGRAM DATA FOR REGION (CACHE CONFIG)
808 */
809 static inline uint16_t
pic12_programregion(uint16_t address,uint16_t region,uint16_t data)810 pic12_programregion(uint16_t address, uint16_t region, uint16_t data)
811 {
812 static int write_pending = 0;
813
814 switch (region) {
815 case PIC_REGIONCONFIG:
816 pic12_conf.config = data;
817 return region;
818 case PIC_REGIONCODE:
819 if (data != PIC_VOID) {
820 if (pic12_map[pic12_index].backupaddr) {
821 if (address == (pic12_map[pic12_index].flash - 1))
822 break;
823 if (address == pic12_map[pic12_index].backupaddr)
824 break;
825 }
826 write_pending = 1;
827 pic12_loadregion(PIC_REGIONCODE, data);
828 }
829 uint16_t mask = pic12_map[pic12_index].nlatches - 1;
830 if (write_pending && ((address & mask) == mask)) {
831 write_pending = 0;
832 pic12_begin_programming();
833 pic12_end_programming();
834 }
835 return region;
836 }
837 if (p.f) fprintf(p.f, "%s: warning: region unsupported [%04X] [%d]\n",
838 __func__, address, region);
839 return PIC_REGIONNOTSUP;
840 }
841
842 /*
843 * GET VERIFY DATA FOR REGION
844 */
845 static inline uint16_t
pic12_verifyregion(uint16_t address,uint16_t region,uint16_t wdata)846 pic12_verifyregion(uint16_t address, uint16_t region, uint16_t wdata)
847 {
848 if (region == PIC_REGIONCODE || region == PIC_REGIONCONFIG)
849 return pic12_read_data_from_program_memory();
850
851 if (p.f) fprintf(p.f, "%s: warning: region unsupported [%d]\n",
852 __func__, region);
853
854 return wdata;
855 }
856
857 /*****************************************************************************
858 *
859 * Program & verify
860 *
861 *****************************************************************************/
862
863 /*
864 * PROGRAM DATA
865 */
866 uint32_t
pic12_program_data(uint32_t current_region,pic_data * pdata)867 pic12_program_data(uint32_t current_region, pic_data *pdata)
868 {
869 static uint16_t PC_address = 0;
870 uint16_t address, new_region, wdata;
871
872 for (uint32_t i = 0; i < pdata->nbytes; i += 2) {
873 address = (pdata->address + i) >> 1;
874 new_region = pic12_getregion(address);
875 if (new_region != current_region) {
876 pic12_programregion(PIC_VOID, PIC_REGIONCODE, PIC_VOID);
877 pic12_program_verify(); /* PC RESET */
878 current_region = pic12_initregion(new_region, &PC_address);
879 }
880 if (current_region == PIC_REGIONNOTSUP)
881 continue;
882 while (address > PC_address) {
883 pic12_programregion(PC_address, PIC_REGIONCODE, PIC_VOID);
884 pic12_increment_address();
885 PC_address++;
886 }
887 wdata = pdata->bytes[i] |
888 (pdata->bytes[i + 1] << 8);
889 wdata &= PIC12_MASK;
890 pic12_programregion(address, current_region, wdata);
891 }
892 return current_region;
893 }
894
895 /*
896 * END PROGRAMMING
897 */
898 void
pic12_program_end(int config)899 pic12_program_end(int config)
900 {
901 pic12_programregion(PIC_VOID, PIC_REGIONCODE, PIC_VOID);
902 pic12_standby();
903 if (config)
904 pic12_write_config();
905 }
906
907 /*
908 * VERIFY DATA
909 */
910 uint32_t
pic12_verify_data(uint32_t current_region,pic_data * pdata,uint32_t * fail)911 pic12_verify_data(uint32_t current_region, pic_data *pdata, uint32_t *fail)
912 {
913 static uint16_t PC_address = 0;
914 uint16_t address, new_region, wdata, vdata;
915
916 for (uint32_t i = 0; i < pdata->nbytes; i += 2) {
917 address = (pdata->address + i) >> 1;
918 new_region = pic12_getregion(address);
919 if (new_region != current_region) {
920 pic12_program_verify(); /* PC RESET */
921 current_region = pic12_initregion(new_region, &PC_address);
922 }
923 if (current_region == PIC_REGIONNOTSUP)
924 continue;
925 while (address > PC_address) {
926 pic12_increment_address();
927 PC_address++;
928 }
929 wdata = (pdata->bytes[i] | pdata->bytes[i + 1] << 8) & PIC12_MASK;
930 vdata = pic12_verifyregion(address, current_region, wdata);
931 if (vdata != wdata) {
932 if (p.f) fprintf(p.f, "%s: error: read [%04X] expected [%04X] at [%04X]\n",
933 __func__, vdata, wdata, address);
934 pdata->bytes[i] = vdata;
935 pdata->bytes[i + 1] = vdata >> 8;
936 (*fail) += 2;
937 }
938 }
939 return current_region;
940 }
941
942 /*
943 * VIEW DATA
944 */
945 void
pic12_view_data(pic_data * pdata)946 pic12_view_data(pic_data *pdata)
947 {
948 uint16_t wdata;
949
950 printf("[%04X] ", pdata->address >> 1);
951 for (uint32_t i = 0; i < pdata->nbytes; i += 2) {
952 wdata = pdata->bytes[i] | (pdata->bytes[i + 1] << 8);
953 wdata &= PIC12_MASK;
954 printf("%04X ", wdata);
955 }
956 putchar('\n');
957 }
958
959 /*****************************************************************************
960 *
961 * Diagnostic functions
962 *
963 *****************************************************************************/
964
965 /*
966 * DUMP DEVICE ID DETAILS
967 */
968 void
pic12_dumpdeviceid(void)969 pic12_dumpdeviceid(void)
970 {
971 printf("[0000] [PROGRAM] %04X WORDS\n", pic12_map[pic12_index].flash);
972
973 if (pic12_map[pic12_index].backupaddr) {
974 printf("[%04X] [OSCCAL] %04X\n",
975 pic12_map[pic12_index].flash - 1,
976 pic12_conf.osccal_reset);
977 }
978
979 if (pic12_map[pic12_index].dataflash) {
980 printf("[%04X] [DATA] %04X BYTES\n",
981 pic12_map[pic12_index].flash,
982 pic12_map[pic12_index].dataflash);
983 }
984
985 for (uint32_t i = 0; i < 4; i++) {
986 printf("[%04X] [USERID%d] %04X %c\n",
987 pic12_map[pic12_index].flash + pic12_map[pic12_index].dataflash + i, i,
988 pic12_conf.userid[i], PIC_CHAR(0xFF & pic12_conf.userid[i]));
989 }
990
991 if (pic12_map[pic12_index].backupaddr) {
992 printf("[%04X] [BACKUP] %04X\n",
993 pic12_map[pic12_index].backupaddr,
994 pic12_conf.osccal_backup);
995 }
996
997 pic12_dumpconfig(PIC_BRIEF, 0);
998 printf(" [DEVICEID] %s\n", pic12_map[pic12_index].devicename);
999 }
1000
1001 /*
1002 * DUMP OSCCAL DETAILS
1003 */
1004 void
pic12_dumposccal(void)1005 pic12_dumposccal(void)
1006 {
1007 if (pic12_map[pic12_index].backupaddr == 0) {
1008 printf("%s: error: OSCCAL is not supported on this device\n", __func__);
1009 } else {
1010 printf("[%04X] [OSCCAL] %04X\n",
1011 pic12_map[pic12_index].flash - 1,
1012 pic12_conf.osccal_reset);
1013 printf("[%04X] [BACKUP] %04X\n",
1014 pic12_map[pic12_index].backupaddr,
1015 pic12_conf.osccal_backup);
1016 }
1017 }
1018
1019 /*
1020 * DUMP CONFIG WORD DETAILS
1021 */
1022 void
pic12_dumpconfig(uint32_t mode,uint32_t partition)1023 pic12_dumpconfig(uint32_t mode, uint32_t partition)
1024 {
1025 printf("[%04X] [CONFIG] %04X\n",
1026 PIC12_CONFIG, pic12_conf.config);
1027 #if VERBOSE
1028 if (mode == PIC_VERBOSE)
1029 pic12_dumpconfig_verbose();
1030 #endif
1031 }
1032
1033 /*
1034 * DUMP VERBOSE CONFIG WORD DETAILS FOR DEVICE
1035 */
1036 #ifdef VERBOSE
1037 void
pic12_dumpconfig_verbose(void)1038 pic12_dumpconfig_verbose(void)
1039 {
1040 /* UNIMPLEMENTED */
1041 }
1042 #endif /* VERBOSE */
1043
1044 /*
1045 * DUMP HEX FLASH WORDS
1046 */
1047 void
pic12_dumphexcode(uint32_t address,uint32_t size,uint32_t * data)1048 pic12_dumphexcode(uint32_t address, uint32_t size, uint32_t *data)
1049 {
1050 uint32_t i, j, nlines = 0;
1051
1052 for (i = 0; i < size; address += 8, i += 8) {
1053 if (pic_mtcode(PIC12_MASK, 8, &data[i]))
1054 continue;
1055 printf("[%04X] ", address);
1056 for (j = 0; j < 8; ++j)
1057 printf("%03X ", data[i + j] & PIC12_MASK);
1058 for (j = 0; j < 8; ++j)
1059 putchar(PIC_CHAR(0xFF & data[i + j]));
1060 putchar('\n');
1061 nlines++;
1062 }
1063 if (!nlines)
1064 printf("%s: information: flash empty\n", __func__);
1065 }
1066
1067 /*
1068 * DUMP INHX32 FLASH WORDS
1069 */
1070 void
pic12_dumpinhxcode(uint32_t address,uint32_t size,uint32_t * data)1071 pic12_dumpinhxcode(uint32_t address, uint32_t size, uint32_t *data)
1072 {
1073 uint32_t i, j;
1074
1075 /* 12-bit: Extended address = 0x0000 */
1076 pic_dumpaddr(0, 1);
1077
1078 for (i = 0; i < size; address += 8, i += 8) {
1079 if (pic_mtcode(PIC12_MASK, 8, &data[i]))
1080 continue;
1081
1082 uint8_t cc, hb, lb;
1083 hb = address >> 7;
1084 lb = address << 1;
1085 printf(":%02X%02X%02X00", 16, hb, lb);
1086 cc = 16 + hb + lb + 0x00;
1087 for (j = 0; j < 8; ++j) {
1088 lb = data[i + j];
1089 hb = data[i + j] >> 8;
1090 printf("%02X%02X", lb, hb);
1091 cc = cc + lb + hb;
1092 }
1093 printf("%02X\n", (0x0100 - cc) & 0xFF);
1094 }
1095 }
1096
1097 /*
1098 * DUMP HEX DATA FLASH WORDS
1099 */
1100 void
pic12_dumphexdata(uint32_t address,uint32_t size,uint16_t * data)1101 pic12_dumphexdata(uint32_t address, uint32_t size, uint16_t *data)
1102 {
1103 uint32_t i, j, nlines = 0;
1104
1105 for (i = 0; i < size; address += 16, i += 16) {
1106 if (pic_mtdata(0xFFF, 16, &data[i]))
1107 continue;
1108 printf("[%04X] ", address);
1109 for (j = 0; j < 16; ++j)
1110 printf("%02X ", data[i + j]);
1111 for (j = 0; j < 16; ++j)
1112 putchar(PIC_CHAR(0xFF & data[i + j]));
1113 putchar('\n');
1114 nlines++;
1115 }
1116 if (!nlines)
1117 printf("%s: information: data empty\n", __func__);
1118 }
1119
1120 /*
1121 * DUMP INHX32 DATA FLASH WORDS
1122 */
1123 void
pic12_dumpinhxdata(uint32_t address,uint32_t size,uint16_t * data)1124 pic12_dumpinhxdata(uint32_t address, uint32_t size, uint16_t *data)
1125 {
1126 uint32_t i, j;
1127
1128 for (i = 0; i < size; address += 8, i += 8) {
1129 if (pic_mtdata(0xFFF, 8, &data[i]))
1130 continue;
1131
1132 uint8_t cc, hb, lb;
1133 hb = address >> 7;
1134 lb = address << 1;
1135 printf(":%02X%02X%02X00", 16, hb, lb);
1136 cc = 16 + hb + lb + 0x00;
1137 for (j = 0; j < 8; ++j) {
1138 lb = data[i + j];
1139 printf("%02X00", lb);
1140 cc = cc + lb + 0x00;
1141 }
1142 printf("%02X\n", (0x0100 - cc) & 0xFF);
1143 }
1144 }
1145
1146 /*
1147 * DUMP DEVICE CONFIGURATION
1148 */
1149 void
pic12_dumpdevice(void)1150 pic12_dumpdevice(void)
1151 {
1152 /* 12-bit: Extended address = 0x0000 */
1153 pic_dumpaddr(0, 1);
1154
1155 /* IDLOC */
1156 uint16_t address = pic12_map[pic12_index].flash + pic12_map[pic12_index].dataflash;
1157 for (uint32_t i = 0; i < 4; ++i) {
1158 pic_dumpword16(address + i, pic12_conf.userid[i]);
1159 }
1160 /* CONFIG */
1161 pic_dumpword16(PIC12_CONFIG, pic12_conf.config);
1162 }
1163