-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathpic18prog.mu4
331 lines (268 loc) · 9.67 KB
/
pic18prog.mu4
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
| This file is part of muforth: https://muforth.dev/
|
| Copyright 2002-2025 David Frech. (Read the LICENSE for details.)
loading PIC18 programming (PIC181xK50)
| NOTE: This is used for programming the 1xK50 parts (and others I'm sure).
| For the PIC18-Q parts, a much simpler SPI-compatible method is used.
hex
| comment %%
| Chip commands:
| 0000 execute core instruction
| 0010 read tablat
| 1000 tblrd*
| 1001 tblrd*+ ( read, post-increment)
| 1010 tblrd*- ( read, post-decrement)
| 1011 tblrd+* ( read, pre-increment)
| 1100 tblwr* ( write)
| 1101 tblwr*+2 ( write, post-increment by 2)
| 1110 tblwrprog*+2 ( write, post-increment by 2, start programming)
| 1111 tblwrprog ( write, start programming)
| %%
: chip constant does> @ ( lo hi cmd) push swap pop pic.Write ;
00 chip core ( execute core instruction)
0c chip write2 ( write two bytes)
0d chip write2+ ( write two bytes, post-increment by 2)
0e chip write2+prog ( write two bytes, post-increment by 2, start programming)
0f chip write2prog ( write two bytes, start programming)
| NOTE: In all these core instructions the "a" bit is 0, meaning that we're
| using "access mode". This maps 00 to 5f to RAM, and 60 to ff to I/O regs
| f60 to fff.
( XXX use the same mnemonics as the assembler? ldi, ld, st, clr?)
: lit ( byte) 0e ( movlw) core ;
: load ( freg) 50 ( movf) core ;
: store ( freg) 6e ( movwf) core ;
: clear ( freg) 6a ( clrf) core ;
: bset ( freg bit) 2* 80 + ( bsf) core ;
: bclr ( freg bit) 2* 90 + ( bcf) core ;
: nop 0 0 core ;
( XXX all these addresses should be come from the equates!)
( Useful addresses:)
0ff8 constant pu ( aka TBLPTRU)
0ff7 constant ph ( aka TBLPTRH)
0ff6 constant pl ( aka TBLPTRL)
0ff5 constant memdata ( aka TABLAT)
( Using FSR0 to access data memory.)
0fef constant x@ ( aka INDF0)
0fee constant x@+ ( aka POSTINC0)
0fed constant x@- ( aka POSTDEC0)
0fec constant x+@ ( aka PREINC0)
0feb constant x@+w ( aka PLUSW0)
0fea constant xh ( aka FSR0H)
0fe9 constant xl ( aka FSR0L)
| If XINST is set, are we in literal offset addressing mode even while
| programming? If so, let's make sure to set FSR2 to zero so that things
| still work as expected.
0fda constant zh ( aka FSR2H)
0fd9 constant zl ( aka FSR2L)
( EEPROM registers)
0faa constant eeadrh ( address register high)
0fa9 constant eeadrl ( address register low)
0fa8 constant eedata
0fa7 constant eecon2 ( aka EECON2)
0fa6 constant eecon ( aka EECON1)
( eecon bits:)
0 constant rd
1 constant wr
2 constant wren
3 constant wrerr
4 constant free
6 constant cfgs
7 constant eepgd
: eeset ( bit) eecon swap bset ;
: eeclr ( bit) eecon swap bclr ;
: p!
>hilo lit pl store
>hilo lit ph store
lit pu store ;
variable ep ( local copy of eeprom pointer; we have to increment it!)
: ep! eecon clear ep ! ;
#eeprom 200 u< .if ( we only need one byte to address the EEPROM)
: e!+
ep @ 1 ep +!
lit eeadrl store ;
.else ( need two bytes of EEPROM address)
: e!+
ep @ 1 ep +!
>hilo lit eeadrl store
lit eeadrh store ;
.then
: x! ( data-addr) ( set X pointer - aka FSR0)
>hilo lit xl store
lit xh store ;
: z! ( data-addr) ( set Z pointer - aka FSR2) ( mostly to zero!)
>hilo lit zl store
lit zh store ;
( Delays)
: us #1000 * ( ns) 0 swap nanosleep ;
: ms #1000 * us ;
( Get a value from W back to the host)
: readw memdata store nop 2 pic.Read ;
| Polled write: after setting WR and writing two NOPs, poll the WR bit of
| EECON1 until clear.
: polled-write
wr eeset nop nop ( write begins now)
( poll WR bit until clear)
begin eecon load readw [ 1 wr << #] and 0= until #100 us ;
( I've chosen these names badly... ;-)
: data@+ x@+ load readw ; ( read data memory)
: data!+ lit x@+ store ; ( write data memory)
: r+ ( read, post inc) 9 pic.Read ; ( read prog memory)
: ee@+ ( - b) ( read eeprom memory)
e!+ rd eeset eedata load readw ;
: ee!+ ( b) ( write eeprom memory)
e!+ lit eedata store polled-write ;
: zpread ( buf addr len) ( read program memory)
swap p! swap m ! for r+ m& next ;
: zread ( buf addr len) ( read data memory)
swap x! swap m ! for data@+ m& next ;
: zwrite ( buf addr len) ( write data memory)
swap x! swap m ! for m* data!+ next ;
: zeread ( buf addr len) ( read eeprom)
swap ep! swap m ! for ee@+ m& next ;
: zewrite ( buf addr len) ( write eeprom)
swap ep! swap m !
wren eeset ( enable EEPROM writes)
for m* ee!+ next
wren eeclr ( disable EEPROM writes) ;
: +prog ( enable programming) pic.Hello pic.+Prog eecon clear ;
: -prog ( disable programming) pic.-Prog pic.Bye ;
( So we can do chat-like things - like dump memory - via ICSP.)
: icsp
chat-via +prog chat-fail ( Run)
zpread zread zeread
zwrite zewrite
chat-fail ( Flash) chat-fail ( Erase) ;
| Procedures for erasing and programming the chip.
|
| Bulk erase:
| Write command to 3c_0004/5, using code 1100, with both bytes equal
| Two NOPs
| Delay for P11 + P10 == 5ms + 100us
|
| Bulk erase commands:
| 0f8f Erase chip
| 0088 Erase user IDs
| 0084 Erase data EEPROM
| 0081 Erase boot block
| 0082 Erase CONFIG bits
| 0180 Erase flash block 0
| 0280 Erase flash block 1
| 0480 Erase flash block 2
| 0880 Erase flash block 3
|
| Row erase:
| Set EEPGD & WREN, clear CFGS in EECON1
| Load pu/ph/pl
| Set FREE & WR in EECON1
| Two NOPs
| Poll WR bit until clear
| Hold PGC low for P10 == 100us
| Clear WREN
|
| Program EEPROM:
| Set WREN, clear EEPGD and CFGS in EECON1
| Load EEADR, EEADRH with address
| Load EEDATA with byte to program
| Set WR in EECON1
| Two NOPs
| Poll WR bit until clear
| Hold PGC low for P10 == 100us
| Clear WREN
|
| Program flash:
| Set EEPGD & WREN, clear CFGS in EECON1
| Load pu/ph/pl
| Repeat code 1101, load two bytes, postinc by 2, all but last two bytes
| code 1111, load last two bytes and program
| XXX: could we use code 1110 instead of 1111 which would post-increment and get us
| ready for the next row?
| code 0000, hold PGC high for P9, low for P10
|
| Program ID:
| Set EEPGD & WREN, clear CFGS in EECON1
| Load pu/ph/pl
| code 1101, load two bytes, postinc by 2
| code 1101, load two bytes, postinc by 2
| code 1101, load two bytes, postinc by 2
| code 1111, load two bytes and program
| code 0000, hold PGC high for P9, low for P10
|
| Program CONFIG byte:
| Set EEPGD, CFGS, and WREN in EECON1
| Set even address in pu/ph/pl
| code 1111, load even byte in both slots
| code 0000, hold PGC high for P9A and low for P10
| Set odd address in pl
| code 1111, load odd byte in both slots
| code 0000, hold PGC high for P9A and low for P10
| Repeat as necessary
| Instead of reusing the memory dump's p pointer - the semantics of which
| are different than they were originally - let's create our own.
variable pp ( programming pointer - contains a target address)
: pp& ( b) pp @ image-c! 1 pp +! ;
: pp* ( - b) pp @ image-c@ 1 pp +! ;
: image-pp@ ( - host-addr) pp @ image+ ;
| XXX programming PDF suggests writing to 3c_0005 before 3c_0004, but
| doesn't say it's *necessary*... this code seems to work. Hmm.
: erase-command ( cmd)
>hilo 3c_0004 p! dup write2
3c_0005 p! dup write2
nop nop 6 ms ;
: erase-chip 0f8f erase-command ;
: prog-config-byte
pp @ 1 pp +! dup config-space c@
dup 0ff = if 2drop ^ then ( skip if 0ff)
swap p! 8 pic.Read ( read config byte) ( ours chip's)
over = if ( already programmed this one) drop ^ then
dup ( high and low bytes the same!) write2prog pic.Config
char . emit ;
| XXX Be careful not to enable the protection of CONFIG bytes, by setting
| WRTC to 0 in CONFIG6H, until *after* writing the other bytes!
: prog-config
cr ." Writing CONFIG bytes"
eepgd eeset cfgs eeset wren eeset ( enable CONFIG writes)
30_0000 pp ! 10 for prog-config-byte next
eecon clear ( reset EECON) ;
| Show progress in chunks the size of the erase page, even if we use bulk
| erase. The programming buffer size is too small a chunk to show.
: prog-region
region over p! swap pp ! ( len)
#program 1- + ( round up) #program / for ( flash buffers to fill)
pp @ [ #erase 1- #] and 0= if cr ." page " pp @ u. then
[ #program 2/ 1- #] for pp* pp* write2+ next ( all but last two bytes)
pp* pp* write2+prog ( last two bytes)
pic.Program
next ;
: prog-flash
eepgd eeset wren eeset
cr ." Writing flash (application)" app prog-region
cr ." Writing flash (signature)" signature prog-region
.ifdef bootloader
cr ." Writing flash (bootloader)" boot prog-region
.then
eecon clear ;
: prog-ee-byte
pp* dup 0ff = if drop ^ then ( skip if 0ff)
ee!+
char . emit ;
: prog-eeprom
cr ." Writing eeprom"
eeprom region over pp ! swap ep! ( len) =if
wren eeset ( enable EEPROM writes)
for prog-ee-byte next
eecon clear ( reset EECON)
^
then drop ;
: prog
cr ." REMINDER: Have you checked in all changes? You should if you want the
signature's commit to be correct!" cr
radix preserve hex
'h preserve image preserve
+prog erase-chip prog-flash prog-eeprom prog-config -prog ;
: verify-flash ;
: verify-eeprom ;
: verify-config ;
: verify
radix preserve hex
'h preserve image preserve
+prog verify-flash verify-eeprom verify-config -prog ;