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