1;
2;
3; Copyright (c) 2013 Roy Rankin
4;
5; This file is part of the gpsim regression tests
6;
7; This library is free software; you can redistribute it and/or
8; modify it under the terms of the GNU Lesser General Public
9; License as published by the Free Software Foundation; either
10; version 2.1 of the License, or (at your option) any later version.
11;
12; This library is distributed in the hope that it will be useful,
13; but WITHOUT ANY WARRANTY; without even the implied warranty of
14; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15; Lesser General Public License for more details.
16;
17; You should have received a copy of the GNU Lesser General Public
18; License along with this library; if not, see
19; <http://www.gnu.org/licenses/lgpl-2.1.html>.
20
21
22        ;; The purpose of this program is to test gpsim's ability to
23        ;; simulate a pic 16F1788.
24        ;; Specifically, basic port operation, eerom, interrupts,
25	;; a2d, dac, SR latch, capacitor sense, and enhanced instructions
26
27
28	list    p=16f1788                ; list directive to define processor
29	include <p16f1788.inc>           ; processor specific variable definitions
30        include <coff.inc>              ; Grab some useful macros
31
32        __CONFIG _CONFIG1, _CP_OFF & _WDTE_ON &  _FOSC_INTOSC & _PWRTE_ON &  _BOREN_OFF & _MCLRE_ON & _CLKOUTEN_OFF
33        __CONFIG _CONFIG2, _STVREN_ON ; & _WRT_BOOT
34
35;------------------------------------------------------------------------
36; gpsim command
37.command macro x
38  .direct "C", x
39  endm
40
41TSEN  EQU H'0005'
42TSRNG EQU H'0004'
43
44;----------------------------------------------------------------------
45GPR_DATA                UDATA_SHR
46cmif_cnt	RES	1
47tmr0_cnt	RES	1
48tmr1_cnt	RES	1
49eerom_cnt	RES	1
50adr_cnt		RES	1
51data_cnt	RES	1
52inte_cnt	RES	1
53iocaf_val	RES	1
54
55  GLOBAL iocaf_val
56
57;----------------------------------------------------------------------
58;   ********************* RESET VECTOR LOCATION  ********************
59;----------------------------------------------------------------------
60RESET_VECTOR  CODE    0x000              ; processor reset vector
61        movlp  high  start               ; load upper byte of 'start' label
62        goto   start                     ; go to beginning of program
63
64
65  .sim "module library libgpsim_modules"
66  ; Use a pullup resistor as a voltage source
67  .sim "module load pullup V1"
68  .sim "V1.resistance = 10000.0"
69  .sim "V1.capacitance = 20e-12"
70  .sim "V1.voltage=1.0"
71
72  .sim "node n1"
73  .sim "attach n1 porta0 porta3"
74  .sim "node n2"
75  .sim "attach n2 porta1 porta4"
76  .sim "node n3"
77  .sim "attach n3 porta2 porta5"
78  .sim "node n4"
79  .sim "attach n4 portb0 V1.pin"
80  .sim "node n5"
81  .sim "attach n5 porta6 porta7"
82  .sim "node n6"
83  .sim "attach n6 portb1 portb7"
84
85  .sim "p16f1788.xpos = 72"
86  .sim "p16f1788.ypos = 72"
87
88  .sim "V1.xpos = 260"
89  .sim "V1.ypos = 120"
90
91
92;------------------------------------------------------------------------
93;
94;  Interrupt Vector
95;
96;------------------------------------------------------------------------
97
98INT_VECTOR   CODE    0x004               ; interrupt vector location
99	; many of the core registers now saved and restored automatically
100
101;        movwf   w_temp
102;        swapf   STATUS,W
103	clrf	BSR		; set bank 0
104;        movwf   status_temp
105
106	btfsc	PIR2,EEIF
107	    goto ee_int
108
109  	btfsc	INTCON,T0IF
110	    goto tmr0_int
111
112  	btfsc	INTCON,IOCIF
113	    goto inte_int
114
115	.assert "'***FAILED p16f1788 unexpected interrupt'"
116	nop
117
118
119; Interrupt from TMR0
120tmr0_int
121	incf	tmr0_cnt,F
122	bcf 	INTCON,T0IF
123	goto	exit_int
124
125; Interrupt from eerom
126ee_int
127	incf	eerom_cnt,F
128	bcf 	PIR2,EEIF
129	goto	exit_int
130
131; Interrupt from INT pin
132inte_int
133	incf	inte_cnt,F
134	BANKSEL	IOCAF
135	movf	IOCAF,W
136	movwf	iocaf_val
137	xorlw	0xff
138	andwf 	IOCAF, F
139	goto	exit_int
140
141exit_int:
142
143        retfie
144
145
146;----------------------------------------------------------------------
147;   ******************* MAIN CODE START LOCATION  ******************
148;----------------------------------------------------------------------
149MAIN    CODE
150start
151	;set clock to 16 Mhz
152	BANKSEL OSCCON
153	bsf 	OSCCON,6
154
155	call  test_pir_pie_bits
156
157	BANKSEL FVRCON
158	; Enable Core Temp, high range, FVR AD 2.048v
159	movlw	(1<<TSEN)|(1<<TSRNG)|(1<<FVREN)|(1<<ADFVR1)
160	movwf	FVRCON
161	BANKSEL STKPTR
162	movf	STKPTR,W
163;	;
164	; test pins in analog mode return 0 on register read
165	BANKSEL TRISA
166	clrf	STATUS
167	clrf	TRISA
168   .assert "trisa == 0x00, '*** FAILED 16f1788  TRISA not clear '"
169	nop
170	BANKSEL PORTA
171	movlw	0xff
172	movwf	PORTA
173   .assert "porta == 0xe8, '*** FAILED 16f1788  analog bits read 0'"
174	nop
175	movf	PORTA,W
176
177;
178; test PORTA works as expected
179;
180	clrf	PORTA
181	BANKSEL ANSELA
182	clrf	ANSELA	; set port to digital
183	bcf	ANSELB,0
184	BANKSEL TRISA
185	movlw	0x38
186	movwf	TRISA		;PORTA 0,1,2 output 3,4,5 input
187
188	clrf	BSR	; bank 0
189  .assert "porta == 0x00, 'PORTA = 0x00'"
190	nop
191	movlw	0x07
192	movwf	PORTA		; drive 0,1,2  bits high
193	bsf	PORTC,7
194  .assert "porta == 0x3f, 'PORTA = 0x3f'"
195	nop
196	BANKSEL LATA
197	movf	LATA,W
198	BANKSEL TRISA
199	movlw	0x07
200	movwf	TRISA  	; PORTA 3, 4, 5 output 0,1,2 input
201	BANKSEL PORTA
202  .assert "porta == 0x00, 'PORTA = 0x00'"
203	nop
204	movlw	0x38
205	movwf	PORTA		; drive output bits high
206  .assert "porta == 0x3f, 'PORTA = 0x3f'"
207	nop
208
209	call test_eerom
210	call test_int
211        call read_config_data
212	call test_a2d
213	call test_dac
214	call test_a2d_ref
215 	call write_prog
216
217  .assert  "'*** PASSED 16f1788 Functionality'"
218	nop
219	reset
220	goto	$
221
222;
223;	Test A/D Vref-pin and differential input
224;
225test_a2d_ref:
226	BANKSEL ANSELA
227	bsf	ANSELA,2
228	bsf	ANSELA,1
229	BANKSEL	TRISA
230	bsf	TRISA,5
231	BANKSEL	DAC1CON0
232	; Pin a2 is both DAC1 output and ADC Vref-pin
233	movlw	(1<<DAC1EN)|(1<<DACOE1)
234	movwf	DAC1CON0
235	movlw	0x10	; Ladder 16/256 * 5V = 0.3125 V
236	movwf	DAC1CON1
237	BANKSEL	ADCON0
238	movlw	(1<<ADFM)|(7 << 4) | (1<<ADNREF) ; 2's comp, Frc, Vref-pin
239	movwf	ADCON1
240	movlw	0xf		; V- = Vref-pin
241	movwf	ADCON2
242	movlw	(1<<ADON)|(0xc<<2)	; V+ = AN12
243	movwf   ADCON0
244	; DAC output  (1V - 0.3125) /(5-0.3125)
245	call	a2dConvert
246   .assert "adresh == 0x02 && (adresl==0x59), '*** FAILED 16f1788 AN12=1V V-=Vref-pin'"
247	nop
248
249  	; Test Vdd = 5.00 as Vsource+ = 2.500 DAC4 (5 bit)
250	BANKSEL DAC4CON0
251	movlw	(1<<DACEN)|(1<<DAC4OE1)
252	movwf	DAC4CON0
253	movlw	0x10		; ladder 16/32
254	movwf	DAC4CON1
255	BANKSEL	ADCON0
256	movlw	(1<<ADFM)|(7 << 4) | (1<<ADNREF) ; 2's comp, Frc, Vref-pin
257	movwf	ADCON1
258	movlw	0x1		; V- =  AN1 (2.5 V)
259	movwf	ADCON2
260	movlw	(1<<ADON)|(0xc<<2)	; V+ = AN12
261	movwf   ADCON0
262	call	a2dConvert
263   .assert "adresh == 0xfa && (adresl==0xe5), '*** FAILED 16f1788 V+=AN12=1V V-=AN1=2.5V 2's comp'"
264	nop
265	BANKSEL	ADCON0
266	movlw	(7 << 4) | (1<<ADNREF) ; sign-mag, Frc, Vref-pin
267	movwf	ADCON1
268	movlw	0x1			; V- =  AN1
269	movwf	ADCON2
270	movlw	(1<<ADON)|(0xc<<2)|(1<<ADRMD)	; V+ = AN12
271	movwf   ADCON0
272	call	a2dConvert
273   .assert "adresh == 0x51 && (adresl==0x81), '*** FAILED 16f1788 V+=AN12=1V V-=AN1=2.5V sign-mag 10bit'"
274	nop
275	BANKSEL DAC4CON0
276	clrf	DAC4CON0
277	BANKSEL DAC1CON0
278	clrf	DAC1CON0
279	return
280
281
282test_pir_pie_bits:
283	BANKSEL PIR1
284	movlw	0xff
285	movwf	PIR1
286   .assert "pir1 == 0xcf, '*** FAILED 16f1788 PIR1 write test'"
287	nop
288	clrf	PIR1
289	movwf	PIR2
290   .assert "pir2 == 0xff, '*** FAILED 16f1788 PIR2 write test'"
291	nop
292	clrf	PIR2
293	movwf	PIR3
294   .assert "pir3 == 0x10, '*** FAILED 16f1788 PIR3 write test'"
295	nop
296	clrf	PIR3
297
298	BANKSEL	PIE1
299	movwf	PIE1
300   .assert "pie1 == 0xff, '*** FAILED 16f1788 PIE1 write test'"
301	nop
302	clrf	PIE1
303	movwf	PIE2
304   .assert "pie2 == 0xff, '*** FAILED 16f1788 PIE2 write test'"
305	nop
306	clrf	PIE2
307	movwf	PIE3
308   .assert "pie3 == 0x10, '*** FAILED 16f1788 PIE3 write test'"
309	nop
310	clrf	PIE3
311	return
312test_dac:
313	BANKSEL ADCON1
314	movlw   (1<<ADFM)| 0x70 ;A2D 2's comp, Frc, Vdd ref+, Vss ref-
315	movwf   ADCON1
316	BANKSEL TRISC		;
317	bsf     TRISC,0		;Set RC0 to input
318	BANKSEL ANSELC		;
319	bsf     ANSELC,0	;Set RC0 to analog
320	BANKSEL ADCON0      	;
321	movlw   (0x1e<<2)|(1<<ADON)	;Select A2D input from DAC1  and ADC on
322	movwf   ADCON0
323	; DAC output should be Vsource- (0)
324	call	a2dConvert
325   .assert "(adresh==0x00) && (adresl==0x00), '*** FAILED 16f1788 DAC default'"
326	nop
327	; test DAC enabled Vout = 5V * (128/256) = 2.5
328	BANKSEL DAC1CON0
329	movlw	0x80
330	movwf	DAC1CON1
331	movlw	(1<<DACEN)
332	movwf	DAC1CON0
333	BANKSEL ADCON0
334	call	a2dConvert
335   .assert "(adresh==0x08) && (adresl==0x00), '*** FAILED 16f1788 DAC enabled 1/2'"
336	nop
337  	; Test  FVR = 4.096 as Vsource+ = 2.048
338	BANKSEL	FVRCON
339	movlw	(1<<FVREN)|(1<<CDAFVR1)|(1<<CDAFVR0)
340	movwf	FVRCON
341	movlw	(1<<DACEN) | (1<<DACPSS1)
342	movwf	DAC1CON0
343	BANKSEL ADCON0
344	call	a2dConvert
345   .assert "(adresh==0x06) && (adresl==0x8d), '*** FAILED 16f1788 DAC enabled 1/2 FVR '"
346	nop
347	banksel TRISB
348	bsf	TRISB,7
349	clrf	TRISE
350
351  	; Test Vdd = 5.00 as Vsource+ = 2.500 DAC4 (5 bit)
352	BANKSEL DAC4CON0
353	movlw	(1<<DACEN)|(1<<DAC4OE1) | (1<<DAC4OE2)
354	movwf	DAC4CON0
355	movlw	0x10		; ladder 16/32
356	movwf	DAC4CON1
357	BANKSEL ADCON0
358	movlw   (0x18<<2)|(1<<ADON)	;Select A2D input from DAC4  and ADC on
359	movwf   ADCON0
360	call	a2dConvert
361   .assert "(adresh==0x08) && (adresl==0x00), '*** FAILED 16f1788 DAC4 enabled 1/2 Vdd '"
362	nop
363
364
365	; Read DAC4 from output pin. (will be slightly lower than 2.500 V)
366	BANKSEL ADCON0
367	movlw   (0x0a<<2)|(1<<ADON)	;Select A2D input from DAC4 output pin
368	movwf   ADCON0
369	call	a2dConvert
370   .assert "(adresh==0x07) && (adresl==0xfd), '*** FAILED 16f1788 DAC4 output pin'"
371	nop
372
373
374	BANKSEL DAC4CON0
375	clrf	DAC4CON0
376
377	return
378
379test_eerom:
380  ;
381  ;	test can write and read to all 128 eeprom locations
382  ;	using intterupts
383        clrf    adr_cnt
384        clrf    data_cnt
385;  setup interrupts
386        bsf     INTCON,PEIE
387        bsf     INTCON,GIE
388	BANKSEL PIE1
389	bsf 	PIE2,EEIE
390	BANKSEL	PIR1
391;
392;	write to EEPROM starting at EEPROM address 0
393;	value of address as data using interrupts to
394;	determine write complete.
395;	read and verify data
396
397l1:
398        movf    adr_cnt,W
399	clrf	eerom_cnt
400	BANKSEL	EEADRL
401        movwf   EEADRL
402        movf    data_cnt,W
403        movwf   EEDATL
404	bcf 	EECON1, CFGS  ;Deselect Configuration space
405	bcf 	EECON1, EEPGD ;Point to DATA memory
406	bsf 	EECON1, WREN  ;Enable writes
407
408
409        bcf     INTCON,GIE      ;Disable interrupts while enabling write
410
411        movlw   0x55            ;Magic sequence to enable eeprom write
412        movwf   EECON2
413        movlw   0xaa
414        movwf   EECON2
415
416        bsf     EECON1,WR      	;Begin eeprom write
417
418        bsf     INTCON,GIE      ;Re-enable interrupts
419	bcf 	EECON1, WREN 	;Disable writes
420
421
422     ;;   clrf   BSR           ; Bank 0
423        movf   eerom_cnt,W
424	skpnz
425        goto   $-2
426;
427;	read what we just wrote
428;
429
430        movf    adr_cnt,W
431
432	BANKSEL	EEADRL
433	movwf   EEADRL
434	bcf EECON1, CFGS 	;Deselect Config space
435	bcf EECON1, EEPGD	;Point to DATA memory
436
437	bsf 	EECON1,RD	; start read operation
438	movf	EEDATL,W	; Read data
439	BANKSEL	PIR1
440
441	xorwf	data_cnt,W	; did we read what we wrote ?
442	skpz
443	goto eefail
444
445        incf    adr_cnt,W
446        andlw   0x7f
447        movwf   adr_cnt
448	movwf	data_cnt
449
450        skpz
451         goto   l1
452
453	return
454
455test_a2d
456	banksel ANSELC
457	clrf	ANSELC
458	BANKSEL ADCON1
459	movlw   0x70 		;Sign-magnatude, Frc, Vdd ref+, Vss ref-
460	movwf   ADCON1
461	movlw	0x0f		;negative input is negative reference
462	movwf	ADCON2
463	BANKSEL TRISC		;
464	bsf     TRISC,0		;Set RC0 to input
465	BANKSEL ANSELC		;
466	bsf     ANSELC,0	;Set RC0 to analog
467	BANKSEL ADCON0      	;
468	movlw   (0xc << 2)|(1<<ADON)	;12bit, Select channel AN12 and ADC on
469	movwf   ADCON0
470	call	a2dConvert
471   .assert "adresh == 0x33 && (adresl==0x30), '*** FAILED 16f1788 AN12=1V'"
472	nop
473  ; measure Core Temperature (v= 2.733 for 30C)
474	bsf 	ADCON1,ADFM	;  2's compliment (right justified)
475        movlw	(0x1d << 2) | (1<<ADON) ; Core Temp channel and AD on
476	movwf	ADCON0
477	call	a2dConvert
478   .assert "(adresh==0x08) && (adresl==0xbf), '*** FAILED 16f1788 ADC Core Temp'"
479	nop
480
481  ; measure FVR (2.048)
482        movlw	(0x1f << 2) | (1<<ADON) ; FVR channel and AD on
483	movwf	ADCON0
484	call	a2dConvert
485   .assert "(adresh==0x06) && (adresl==0x8d), '*** FAILED 16f1788 ADC FVR'"
486	nop
487
488  ; measure FVR using FVR Reference
489	movlw	0xf3	; use FVR reference
490	movwf	ADCON1
491        movlw	(0x1f << 2) | (1<<ADON) ; FVR channel and AD on
492	movwf	ADCON0
493	call	a2dConvert
494   .assert "(adresh==0x0f) && (adresl==0xff), '*** FAILED 16f1788 ADC FVR with FVR Ref'"
495	nop
496
497	return
498
499;
500;	Start A2D conversion and wait for results
501;
502a2dConvert
503	bsf 	ADCON0,GO
504	btfsc	ADCON0,GO
505	goto	$-1
506	movf	ADRESH,W
507	return
508
509
510eefail:
511  .assert "'***FAILED 16f1788 eerom write/read error'"
512	nop
513
514test_tmr0:
515	return
516
517
518
519
520
521
522test_int:
523	BANKSEL TRISA
524	bsf     TRISA,2
525        bcf     TRISA,5
526	BANKSEL PORTA
527	clrf	PORTA
528	BANKSEL IOCAP
529	bsf 	IOCAP,2		; set interrupt on + edge of porta2
530
531	BANKSEL OPTION_REG
532	bsf 	OPTION_REG,INTEDG
533	BANKSEL INTCON
534	movlw	0x7f
535	movwf	INTCON
536   .assert "intcon == 0x7e, '*** FAILED 16f1788 INT test - INTCON:IOCIF read only'"
537	nop
538	BANKSEL	IOCAF
539	movlw	0xff
540	movwf	IOCAF
541 .assert "iocaf == 0xff, '*** FAILED 16f1788 INT test - IOCAF writable bits'"
542	nop
543	clrf	IOCAF
544	movwf	IOCBF
545 .assert "iocbf == 0xff, '*** FAILED 16f1788 INT test - IOCBF writable bits'"
546	nop
547	clrf	IOCBF
548	movwf	IOCCF
549 .assert "ioccf == 0xff, '*** FAILED 16f1788 INT test - IOCCF writable bits'"
550	nop
551	clrf	IOCCF
552	movwf	IOCEF
553 .assert "iocef == 0x08, '*** FAILED 16f1788 INT test - IOCEF writable bits'"
554	nop
555	clrf	IOCEF
556	clrf	INTCON
557        bsf     INTCON,GIE      ;Global interrupts
558        bsf     INTCON,IOCIE
559
560 	BANKSEL PORTA
561
562        clrf    inte_cnt
563        bsf     PORTA,5          ; make a rising edge
564        nop
565        movf    inte_cnt,w
566   .assert "W == 0x01, '*** FAILED 16f1788 INT test - No int on rising edge'"
567        nop
568   .assert "iocaf_val == 0x04, '*** FAILED 16f1788 IOCAF bit 2 not set'"
569	nop
570        clrf    inte_cnt
571        bcf     PORTA,5          ; make a falling edge
572        nop
573        movf    inte_cnt,w
574   .assert "W == 0x00, '*** FAILED 16f1788 INT test - Unexpected int on falling edge'"
575        nop
576
577
578;	Setup - edge interrupt
579	BANKSEL IOCAP
580	clrf	IOCAP
581	bsf 	IOCAN,2
582	movlw	0xff
583	clrf	IOCAF
584	BANKSEL INTCON
585        bcf     INTCON,IOCIF     ;Clear flag
586
587        clrf    inte_cnt
588        bsf     PORTA,5          ; make a rising edge
589        nop
590        movf    inte_cnt,w
591   .assert "W == 0x00, '*** FAILED 16f1788 INT test - Unexpected int on rising edge'"
592        nop
593        clrf    inte_cnt
594        bcf     PORTA,5          ; make a falling edge
595        nop
596        movf    inte_cnt,w
597   .assert "W == 0x01, '*** FAILED 16f1788 INT test - No int on falling edge'"
598        nop
599   .assert "iocaf_val == 0x04, '*** FAILED 16f1788 IOCAF bit 2 not set'"
600	nop
601
602
603        return
604
605; read STKPTR, TOSL and cause underflow
606rrr:
607	nop
608	BANKSEL STKPTR
609	movf 	STKPTR,W
610	movf	TOSL,W
611  ;	clrf	TOSL
612	call	rrr2
613	return
614
615; use STKPTR to cause stack underflow
616rrr2:
617	BANKSEL STKPTR
618	movlw	0x1f
619	movwf	STKPTR	;; cause stack underflow
620	return
621
622; overflow stack with recursive call
623rrr3:
624	call rrr3
625	return
626
627
628;
629; Test reading and writing Configuration data via eeprom interface
630read_config_data:
631	;Read DeviceID at address 0x06 from config data
632	BANKSEL  EEADRL            ; Select correct Bank
633	movlw	0x06              ;
634	movwf	EEADRL            ; Store LSB of address
635	clrf	EEADRH            ; Clear MSB of address
636	bsf 	EECON1,CFGS       ; Select Configuration Space
637	bcf 	INTCON,GIE        ; Disable interrupts
638	bsf 	EECON1,RD         ; Initiate read
639	nop
640	nop
641	bsf 	INTCON,GIE        ; Restore interrupts
642   .assert "eedath == 0x30 && eedatl == 0x2b, '*** FAILED 16f1788 Device ID'"
643	nop
644
645  ; test write which is in EEDATAH and EEDATAL to userID1
646	BANKSEL PIR2
647	clrf	PIR2
648	BANKSEL EECON1
649	movlw	0x01              ;
650	movwf	EEADRL            ; Store LSB of address
651	bsf 	EECON1, WREN  	   ;Enable writes
652	bcf 	INTCON,GIE	   ; disable interupts
653        movlw	0x55               ;Magic sequence to enable eeprom write
654        movwf	EECON2
655        movlw	0xaa
656        movwf	EECON2
657	bsf 	EECON1,WR
658	nop
659	nop
660	bsf  	INTCON,GIE
661	bcf 	EECON1, WREN  ;Enable writes
662	BANKSEL PIR2
663	btfss	PIR2,EEIF
664        goto	$-1
665  .assert "UserID2 == 0x302b, '*** FAILED 16f1788 write to UserID2'"
666	nop
667	return
668
669clear_prog:
670; This row erase routine assumes the following:
671; 1. A valid address within the erase block is loaded in ADDRH:ADDRL
672; 2. ADDRH and ADDRL are located in shared data memory 0x70 - 0x7F
673	bcf       INTCON,GIE     ; Disable ints so required sequences will execute properly
674        BANKSEL   EEADRL
675 	movlw	0
676        movwf   EEADRL
677	movlw	3
678        movwf   EEADRH
679        bsf     EECON1,EEPGD   ;   Point to program memory
680        bcf     EECON1,CFGS    ;   Not configuration space
681        bsf     EECON1,FREE    ;   Specify an erase operation
682        bsf     EECON1,WREN    ;   Enable writes
683        movlw   0x55           ;   Start of required sequence to initiate erase
684        movwf   EECON2
685        movlw   0xAA           ;
686        movwf   EECON2
687        bsf     EECON1,WR      ;   Set WR bit to begin erase
688        nop
689        nop
690        bcf     EECON1,WREN    ; Disable writes
691        bsf 	INTCON,GIE     ; Enable interrupts
692	btfsc 	EECON1,WR
693        goto   $-2
694	return
695
696write_prog:
697
698	bcf 	INTCON,GIE      ;   Disable ints so required sequences will execute properly
699	BANKSEL	EEADRH          ;   Bank 3
700	movlw	0x03
701	movwf	EEADRH          ;
702	movlw	0x00
703	movwf	EEADRL          ;
704	movlw	0x00
705	movwf	FSR0L           ;
706	movlw	0x20		;   Program memory
707	movwf	FSR0H           ;
708	bsf 	EECON1,EEPGD    ;   Point to program memory
709	bcf 	EECON1,CFGS     ;   Not configuration space
710	bsf 	EECON1,WREN     ;   Enable writes
711	bsf 	EECON1,LWLO     ;   Only Load Write Latches
712LOOP
713	moviw	FSR0++          ; Load first data byte into lower
714	movwf	EEDATL          ;
715	moviw	FSR0++          ; Load second data byte into upper
716	movwf	EEDATH          ;
717	movf	EEADRL,W        ; Check if lower bits of address are '000'
718	xorlw	0x07            ; Check if we're on the last of 8 addresses
719	andlw	0x07            ;
720	btfsc	STATUS,Z        ; Exit if last of eight words,
721	goto	START_WRITE     ;
722	movlw	0x55            ;   Start of required write sequence:
723	movwf	EECON2
724	movlw	0xAA
725	movwf	EECON2
726	bsf 	EECON1,WR       ;   Set WR bit to begin write
727	nop
728	nop
729	incf	EEADRL,F        ; Still loading latches Increment address
730	goto	LOOP            ; Write next latches
731START_WRITE
732	bcf 	EECON1,LWLO     ; No more loading latches - Actually start Flash program
733	;	memory write
734	movlw	0x55             ;   Start of required write sequence:
735	movwf	EECON2
736	movlw	0xAA            ;
737	movwf	EECON2
738	bsf 	EECON1,WR       ;   Set WR bit to begin write
739	nop
740	nop
741	bcf 	EECON1,WREN     ; Disable writes
742	bsf 	INTCON,GIE      ; Enable interrupts
743	return
744
745 	org 0x200
746rrDATA
747	dw 0x01, 0x02, 0x03
748  end
749