HWA
Bare metal programming with style
fla_2.h
Go to the documentation of this file.
1 
2 /* This file is part of the HWA project.
3  * Copyright (c) 2012,2015 Christophe Duparquet.
4  * All rights reserved. Read LICENSE.TXT for details.
5  */
6 
22 #define hw_read__fla , _hw_read_fla
23 #define _hw_read_fla(o,a,addr,...) _hw_flardbyte((intptr_t)(addr)) HW_EOL(__VA_ARGS__)
24 
25 HW_INLINE uint8_t _hw_flardbyte( uint16_t a )
26 {
27  /* FIXME: Z (R31:R30) is not modified by LPM but GCC considers it is as it reloads
28  Z even if it does not change */
29  uint8_t r ;
30  hw_asm(" lpm %[r], Z" "\n"
31  :
32  [r] "=&r" (r)
33  :
34  "z" (a)
35  );
36  return r ;
37 }
38 
39 
51 #define hw_read_bytes__fla , _hw_read_bytes_fla
52 
53 #define _hw_read_bytes_fla(o,a,dst,addr,n,...) _hw_flardbytes(dst,addr,n) HW_EOL(__VA_ARGS__)
54 
55 /* Store into dst count bytes read from Flash memory address addr
56  */
57 HW_INLINE void _hw_flardbytes( uint8_t *dst, uint16_t addr, uint8_t count )
58 {
59  hw_asm("1: lpm __tmp_reg__, Z+" "\n"
60  " st %a2+, __tmp_reg__" "\n"
61  " dec %A0" "\n"
62  " brne 1b" "\n"
63  :
64  "=r" (count),
65  "=z" (addr),
66  "=e" (dst)
67  :
68  "0" (count), "1" (addr), "2" (dst)
69  );
70 }
71 
72 
99 #define hw_load_buffer__fla , _hw_fla_load_buffer
100 #define _hw_fla_load_buffer(o,a,src,...) _hw_fla_ldpgbf(o,src) HW_EOL(__VA_ARGS__)
101 
102 #define hw_erase_page__fla , _hw_fla_erase_page
103 #define _hw_fla_erase_page(o,a,src,...) _hw_fla_pgers(o,src) HW_EOL(__VA_ARGS__)
104 
105 #define hw_write_page__fla , _hw_fla_write_page
106 #define _hw_fla_write_page(o,a,src,...) _hw_fla_pgwrt(o,src) HW_EOL(__VA_ARGS__)
107 
108 
109 #if !defined HW_DEVICE_FUSE_BOOTRST
110 /*
111  * Device without boot section: the MCU is halted when the flash memory is
112  * busy, no need to wait for readiness
113  */
114 #define _hw_fla_pgers(o, ptr) \
115  do { \
116  _hw_write( o, csr, 1<<HW_POSITION((o, pgers)) | 1<<HW_POSITION((o, spmen)) ); \
117  _hw_fla_spm( ptr ); \
118  }while(0)
119 
120 #define _hw_fla_pgwrt(o, ptr) \
121  do { \
122  _hw_write( o, csr, 1<<HW_POSITION((o, pgwrt)) | 1<<HW_POSITION((o, spmen)) ); \
123  _hw_fla_spm( ptr ); \
124  }while(0)
125 
126 
127 /* Preload Z register before outputting SPM instruction
128  */
129 HW_INLINE void _hw_fla_spm( intptr_t ptr )
130 {
131  hw_asm(" spm \n"
132  :: "z" (ptr) :
133  );
134 }
135 
136 
137 #define _hw_fla_ldpgbf(o, src) \
138  do { \
139  hw_asm("CSR = " HW_Q(HW_ADDRESS((o, csr))-0x20) "\n" \
140  "BP_RWWSRE = " HW_Q(HW_POSITION((o, rwwsre))) "\n" \
141  "BP_SPMEN = " HW_Q(HW_POSITION((o, spmen))) "\n" \
142  "PGSIZE = " HW_Q(HW_DEVICE_FLASH_PAGE_SIZE) "\n" \
143  ); \
144  _hw___fla_ldpgbf( src ); \
145  }while(0)
146 
147 
148 /* Load page buffer with data from src
149  */
150 HW_INLINE void _hw___fla_ldpgbf( void *src )
151 {
152  uint8_t r1 ;
153 
154 #if HW_DEVICE_FLASH_PAGE_SIZE > 256
155 # error
156 #endif
157 
158  hw_asm(
159  /* Clear page buffer
160  */
161  " ldi %[r1], 1<<BP_RWWSRE|1<<BP_SPMEN \n"
162  " .if CSR < 0x40 \n"
163  " out CSR, %[r1] \n"
164  " .else \n"
165  " sts CSR+0x20, %[r1] \n"
166  " .endif \n"
167 
168  /* Load page buffer
169  */
170  " clr r30 \n"
171  " clr r31 \n"
172  "1: ld r0, %a2+ \n"
173  " ld r1, %a2+ \n"
174 
175  " .if CSR < 0x20 \n"
176  " sbi CSR, BP_SPMEN \n"
177  " .else \n"
178  " ldi %[r1], 1<<BP_SPMEN \n"
179  " .if CSR < 0x40 \n"
180  " out CSR, %[r1] \n"
181  " .else \n"
182  " sts CSR+0x20, %[r1] \n"
183  " .endif \n"
184  " .endif \n"
185  " spm \n"
186 
187  " adiw r30, 2 \n"
188  " cpi r30, PGSIZE \n"
189  " brne 1b \n"
190  :
191  [r1] "=r" (r1),
192  "=e" (src)
193  :
194  "1" (src)
195  :
196  "r0", "r1",
197  "r30", "r31"
198  );
199 }
200 
201 #else
202 /*
203  * Device with boot section: the MCU is not halted when programming a page in
204  * the RWW section, must wait the completion of the last SPM operation
205  */
206 #define _hw_fla_pgers(o, ptr) \
207  do { \
208  hw_asm("wdr"); \
209  _hw___fla_dospm( HW_ADDRESS((o,csr)), ptr, \
210  1<<HW_POSITION((o, pgers)) | 1<<HW_POSITION((o, spmen))); \
211  }while(0)
212 
213 #define _hw_fla_pgwrt(o, ptr) \
214  do { \
215  hw_asm("wdr"); \
216  _hw___fla_dospm( HW_ADDRESS((o,csr)), ptr, \
217  1<<HW_POSITION((o, pgwrt)) | 1<<HW_POSITION((o, spmen))); \
218  }while(0)
219 
220 /*
221  */
222 HW_INLINE void _hw___fla_dospm( intptr_t csr, intptr_t ptr, uint8_t cmd )
223 {
224  if ( csr-0x20 < 0x20 ) {
225  hw_asm(" out CSR, %[r1] \n"
226  " spm \n"
227  "1: sbic CSR, BP_SPMEN \n"
228  " rjmp 1b \n"
229  " out CSR, 1<<BP_RWWSRE | 1<<BP_SPMEN \n"
230  " spm \n"
231  "1: sbic CSR, BP_SPMEN \n"
232  " rjmp 1b \n"
233  : [r1] "=r" (cmd)
234  : "z" (ptr) :
235  );
236  }
237  else if ( csr-0x20 < 0x40 ) {
238  hw_asm(" out CSR, %[r1] \n"
239  " spm \n"
240  "1: in %[r1], CSR \n"
241  " sbrc %[r1], BP_SPMEN \n"
242  " rjmp 1b \n"
243  " out CSR, 1<<BP_RWWSRE | 1<<BP_SPMEN \n"
244  " spm \n"
245  "1: in %[r1], CSR \n"
246  " sbrc %[r1], BP_SPMEN \n"
247  " rjmp 1b \n"
248  : [r1] "=r" (cmd)
249  : "0" (cmd), "z" (ptr) :
250  );
251  }
252  else {
253  hw_asm(" sts CSR+0x20, %[r1] \n"
254  " spm \n"
255  "1: lds %[r1], CSR+0x20 \n"
256  " sbrc %[r1], BP_SPMEN \n"
257  " rjmp 1b \n"
258  " out CSR, 1<<BP_RWWSRE | 1<<BP_SPMEN \n"
259  " spm \n"
260  "1: lds %[r1], CSR+0x20 \n"
261  " sbrc %[r1], BP_SPMEN \n"
262  " rjmp 1b \n"
263  : [r1] "=r" (cmd)
264  : "z" (ptr) :
265  );
266  }
267 }
268 
269 
270 #define _hw_fla_ldpgbf(o, src) \
271  do { \
272  hw_asm("CSR = " HW_Q(HW_ADDRESS((o, csr))-0x20) "\n" \
273  "BP_RWWSRE = " HW_Q(HW_POSITION((o, rwwsre))) "\n" \
274  "BP_SPMEN = " HW_Q(HW_POSITION((o, spmen))) "\n" \
275  "PGSIZE = " HW_Q(HW_DEVICE_FLASH_PAGE_SIZE) "\n" \
276  ); \
277  _hw___fla_ldpgbf( src ); \
278  }while(0)
279 
280 
281 /* Load page buffer with data from src
282  */
283 HW_INLINE void _hw___fla_ldpgbf( void *src )
284 {
285  uint8_t r1 ;
286 
287 #if HW_DEVICE_FLASH_PAGE_SIZE > 256
288 # error
289 #endif
290 
291  hw_asm(/* Load page buffer
292  */
293  " clr r30 \n"
294  " clr r31 \n"
295  "1: ld r0, %a2+ \n"
296  " ld r1, %a2+ \n"
297 
298  " .if CSR < 0x20 \n"
299  " sbi CSR, BP_SPMEN \n"
300  " .else \n"
301  " ldi %[r1], 1<<BP_SPMEN \n"
302  " .if CSR < 0x40 \n"
303  " out CSR, %[r1] \n"
304  " .else \n"
305  " sts CSR+0x20, %[r1] \n"
306  " .endif \n"
307  " .endif \n"
308  " spm \n"
309 
310  " adiw r30, 2 \n"
311  " cpi r30, PGSIZE \n"
312  " brne 1b \n"
313  :
314  [r1] "=r" (r1),
315  "=e" (src)
316  :
317  "1" (src)
318  :
319  "r0", "r1",
320  "r30", "r31"
321  );
322 }
323 #endif /* !defined HW_DEVICE_BOOTRST */
324 
325 
326 #if 0 /* Alternate version */
327 HW_INLINE void _hw___fla_ldpgbf( intptr_t dst, void *src )
328 {
329  uint8_t r1, r2 ;
330 
331  hw_asm(
332  /* Clear page buffer
333  */
334  " ldi %[r1], 1<<BP_RWWSRE|1<<BP_SPMEN \n"
335  " .if CSR < 0x40 \n"
336  " out CSR, %[r1] \n"
337  " .else \n"
338  " sts CSR+0x20, %[r1] \n"
339  " .endif \n"
340 
341  /* Load page buffer
342  */
343  " ldi %[r1], " HW_Q(HW_DEVICE_FLASH_PAGE_SIZE/2) "\n"
344  "1: ld r0, %a2+ \n"
345  " ld r1, %a2+ \n"
346 
347  " .if CSR < 0x20 \n"
348  " sbi CSR, BP_SPMEN \n"
349  " .else \n"
350  " ldi %[r2], 1<<BP_SPMEN \n"
351  " .if CSR < 0x40 \n"
352  " out CSR, %[r2] \n"
353  " .else \n"
354  " sts CSR+0x20, %[r2] \n"
355  " .endif \n"
356  " .endif \n"
357  " spm \n"
358 
359  " adiw R30, 2 \n"
360  " dec %[r1] \n"
361  " brne 1b \n"
362  :
363  [r1] "=r" (r1),
364  [r2] "=r" (r2),
365  "=e" (src), "=z" (dst)
366  :
367  "2" (src), "3" (dst)
368  :
369  "r0", "r1"
370  );
371 }
372 #endif
373 
374 
HW_DEVICE_FLASH_PAGE_SIZE
#define HW_DEVICE_FLASH_PAGE_SIZE
Definition: atmega168x.h:37
HW_Q
#define HW_Q(...)
Build a C string from a list of elements.
Definition: hwa_macros.h:448
hw_asm
#define hw_asm(...)
Insert inline assembler code.
Definition: hwa_2.h:37