1 /* Name: spminterface.h 
   2  * Project: USBaspLoader 
   3  * Author: Stephan Baerwolf 
   4  * Creation Date: 2012-08-01 
   5  * Copyright: (c) 2012 by Stephan Baerwolf 
   6  * License: GNU GPL v2 (see License.txt) 
  10 #ifndef SPMINTERFACE_H_f70ba6adf7624275947e859bdbff0599 
  11 #define SPMINTERFACE_H_f70ba6adf7624275947e859bdbff0599 
  14  * spminterface.h offers a lightweight interface by inserting 
  15  * an small machine-subroutine into the bootsection. (right  
  16  * after the interrupt-vector-table) 
  17  * This subroutine can be called by normal code in order to  
  18  * enable it to program the flash (and depending on BLB11-lockbit 
  19  * also the bootsection itself). Since SPM-calls from RWW-sections 
  20  * will fail to work. The routine will be called "bootloader__do_spm". 
  21  * Its principle assembler-code is depicted below (real code is a 
  22  * little machinedependend). 
  23  * Interfaces will be the 8-bit registers r10..r13, for details  
  24  * also see below. As also the pageaddress-registes (Z and rampZ) 
  25  * are interfaced via different registers, it is possible to call 
  26  * this routine via indirect call (icall). 
  27  * Traditionally it is also possible to rcall, therefore you can 
  28  * define "bootloader__do_spm" for your normal code via defsym at  
  30  * Example for an atmega8: "-Wl,--defsym=transfer_point=0x1826" 
  31  * (since BOOTLOADER_ADDRESS is 0x1800 and there are  
  32  * 2x19 = 38 = 0x26 byte for interrupts) 
  36 ;disable interrupts (if enabled) before calling! 
  37 ;you may also want to disable wdt, since this routine may busy-loop 
  38 ;================================================================== 
  40 ;#if HAVE_SPMINTEREFACE_MAGICVALUE 
  41 ;magicvalue in                                    r23:r22:r21:r20 
  43 ;spmcr (spmcrval determines SPM action) will be register:       r18 
  44 ;MCU dependend RA(MPZ should be transfered within register:     r11 
  45 ;lo8(Z) should be transfered within register:                   r12 
  46 ;hi8(Z) should be transfered within register:                   r13 
  47 ;( as definition of SPM low8bit of dataword are stored within   r0 ) 
  48 ;( as definition of SPM hi8bit  of dataword are stored within   r1 ) 
  51 ;temp0 will be register:                                        r11 
  52 ;temp1 will be register:                                        r12 
  53 ;temp2 will be register:                                        r13 
  54 ;spmcrval (r18) may also be changed due to rww reenable-phase   r18 
  55 ;Z (r31:r30) wil be changed during operation 
  58 ;================================================================== 
  59 ; TODO: waitA and waitB could be merged to subroutine saving 2 opc 
  60 ;================================================================== 
  61 ;<magicvalue specific code (not depicted here)> 
  62 ;load pageaddress (Z) from (r11:)r13:12 since it may was used for icall 
  67 waitA:                  ;check for pending SPM complete 
  72 out     SPMCR, spmcrval ;SPM timed sequence 
  75 waitB:                  ;check for previous SPM complete 
  80 ;avoid crash of userapplication 
  81 ldi     spmcrval, ((1<<RWWSRE) | (1<<SPMEN))  
  92 #include "bootloaderconfig.h" 
  97  * This MACRO commands the linker to place correspondig 
  98  * data on the top of the firmware. (Right after the  
  99  * interrupt-vector-table) 
 100  * This is necessary to always locate the 
 101  * "bootloader__do_spm" for example at 0x1826, even if 
 102  * there are existing PROGMEM within the firmware... 
 104 #define BOOTLIBLINK __attribute__ ((section (".vectors") )) 
 107 #ifndef funcaddr___bootloader__do_spm 
 108   #if (defined(BOOTLOADER_ADDRESS)) && (!(defined(NEW_BOOTLOADER_ADDRESS))) 
 109     #if HAVE_SPMINTEREFACE 
 110       #define  funcaddr___bootloader__do_spm (&bootloader__do_spm) 
 113     #if defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__) 
 114       #define  funcaddr___bootloader__do_spm 0x1826 
 115     #elif defined (__AVR_ATmega32__) 
 116       #define  funcaddr___bootloader__do_spm 0x7054 
 117     #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__) || defined (__AVR_ATmega88A__) || defined (__AVR_ATmega88PA__)   
 118       #define  funcaddr___bootloader__do_spm 0x1834 
 119     #elif defined (__AVR_ATmega164A__) || defined (__AVR_ATmega164P__) || defined (__AVR_ATmega164PA__)   
 120       #define  funcaddr___bootloader__do_spm 0x387c 
 121     #elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) || defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168PA__)   
 122       #define  funcaddr___bootloader__do_spm 0x3868 
 123     #elif defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__) || defined (__AVR_ATmega324PA__) 
 124       #define  funcaddr___bootloader__do_spm 0x707c 
 125     #elif defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) 
 126       #define  funcaddr___bootloader__do_spm 0x7068 
 127     #elif defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) 
 128       #define  funcaddr___bootloader__do_spm 0xe07c 
 129     #elif defined (__AVR_ATmega128__) 
 130       #define  funcaddr___bootloader__do_spm 0x1e08c 
 131     #elif defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__) 
 132       #define  funcaddr___bootloader__do_spm 0x1e08c 
 134       #error "unknown MCU - where is bootloader__do_spm located?" 
 141  * Call the "bootloader__do_spm"-function, located within the BLS via comfortable C-interface 
 142  * During operation code will block - disable or reset watchdog before call. 
 144  * ATTANTION:   Since the underlying "bootloader__do_spm" will automatically reenable the 
 145  *              rww-section, only one way to program the flash will work. 
 146  *              (First erase the page, then fill temp. buffer, finally program...) 
 147  *              Since unblocking rww-section erases the temp. pagebuffer (which happens 
 148  *              after a page-erase), first programming this buffer does not help !! 
 150  * REMEMBER: interrupts have to be disabled! (otherwise code may crash non-deterministic) 
 153 #if HAVE_SPMINTEREFACE_MAGICVALUE 
 154 #define __do_spm_Ex     __do_spm_Ex_magic 
 156 #define __do_spm_Ex     __do_spm_Ex_ 
 159 #define __do_spm_Ex_(flash_wordaddress, spmcrval, dataword, ___bootloader__do_spm__ptr) \ 
 165     "mov r13, %B[flashaddress]\n\t"                                                             \ 
 166     "mov r12, %A[flashaddress]\n\t"                                                             \ 
 167     "mov r11, %C[flashaddress]\n\t"                                                             \ 
 169     /* also load the spmcrval */                                                                \ 
 170     "mov r18, %[spmcrval]\n\t"                                                                  \ 
 173     "mov r1, %B[data]\n\t"                                                                      \ 
 174     "mov r0, %A[data]\n\t"                                                                      \ 
 176     /* finally call the bootloader-function */                                                  \ 
 180      * bootloader__do_spm should change spmcrval (r18) to                                       \ 
 181      * "((1<<RWWSRE) | (1<<SPMEN))" in case of success                                          \ 
 183     "cpi r18, %[spmret]\n\t"                                                                    \ 
 184      /* loop infitinte if not so, most likely we called an bootloader__do_spm                   \ 
 185       * with wrong magic! To avoid calls to wrong initialized pages, better crash here...    \ 
 194     : [flashaddress] "r" (flash_wordaddress),                                                   \ 
 195       [spmfunctionaddress] "z" ((uint16_t)(___bootloader__do_spm__ptr)),                        \ 
 196       [spmcrval] "r" (spmcrval),                                                                \ 
 197       [data] "r" (dataword),                                                                    \ 
 198       [spmret] "M" ((1<<RWWSRE) | (1<<SPMEN))                                                   \ 
 199     : "r0","r1","r11","r12","r13","r18"                                                 \ 
 203 #define __do_spm_Ex_magic(flash_wordaddress, spmcrval, dataword, ___bootloader__do_spm__ptr)    \ 
 209     "ldi r23, %[magicD] \n\t"                                                                   \ 
 210     "ldi r22, %[magicC] \n\t"                                                                   \ 
 211     "ldi r21, %[magicB] \n\t"                                                                   \ 
 212     "ldi r20, %[magicA] \n\t"                                                                   \ 
 214     "mov r13, %B[flashaddress]\n\t"                                                             \ 
 215     "mov r12, %A[flashaddress]\n\t"                                                             \ 
 216     "mov r11, %C[flashaddress]\n\t"                                                             \ 
 218     /* also load the spmcrval */                                                                \ 
 219     "mov r18, %[spmcrval]\n\t"                                                                  \ 
 222     "mov r1, %B[data]\n\t"                                                                      \ 
 223     "mov r0, %A[data]\n\t"                                                                      \ 
 225     /* finally call the bootloader-function */                                                  \ 
 229      * bootloader__do_spm should change spmcrval (r18) to                                       \ 
 230      * "((1<<RWWSRE) | (1<<SPMEN))" in case of success                                          \ 
 232     "cpi r18, %[spmret]\n\t"                                                                    \ 
 233      /* loop infitinte if not so, most likely we called an bootloader__do_spm                   \ 
 234       * with wrong magic! To avoid calls to wrong initialized pages, better crash here...    \ 
 243     : [flashaddress] "r" (flash_wordaddress),                                                   \ 
 244       [spmfunctionaddress] "z" ((uint16_t)(___bootloader__do_spm__ptr)),                        \ 
 245       [spmcrval] "r" (spmcrval),                                                                \ 
 246       [data] "r" (dataword),                                                                    \ 
 247       [spmret] "M" ((1<<RWWSRE) | (1<<SPMEN)),                                                  \ 
 248       [magicD] "M" ((HAVE_SPMINTEREFACE_MAGICVALUE>>24)&0xff),                          \ 
 249       [magicC] "M" ((HAVE_SPMINTEREFACE_MAGICVALUE>>16)&0xff),                          \ 
 250       [magicB] "M" ((HAVE_SPMINTEREFACE_MAGICVALUE>> 8)&0xff),                          \ 
 251       [magicA] "M" ((HAVE_SPMINTEREFACE_MAGICVALUE>> 0)&0xff)                                   \ 
 252     : "r0","r1","r11","r12","r13","r18","r20","r21","r22","r23"                         \ 
 257 #if (!(defined(BOOTLOADER_ADDRESS))) || (defined(NEW_BOOTLOADER_ADDRESS)) 
 258 void do_spm(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
) { 
 259     __do_spm_Ex(flash_byteaddress
, spmcrval
, dataword
, funcaddr___bootloader__do_spm 
>> 1); 
 263 #if HAVE_SPMINTEREFACE_NORETMAGIC 
 264   #define bootloader__do_spm_magic_exitstrategy(a) (0xf7f9) 
 266   #define bootloader__do_spm_magic_exitstrategy(a) (a) 
 269 #if (HAVE_SPMINTEREFACE) && (defined(BOOTLOADER_ADDRESS)) && (!(defined(NEW_BOOTLOADER_ADDRESS))) 
 272  * insert architecture dependend "bootloader_do_spm"-code 
 274  * try to make this array as big as possible 
 275  * (so bootloader always uses 2kbytes flash) 
 277 #if defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__) || defined (__AVR_ATmega32__) 
 279 #if defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__) 
 280   #if (BOOTLOADER_ADDRESS != 0x1800) 
 281     #error BOOTLOADER_ADDRESS!=0x1800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 283 #elif defined (__AVR_ATmega32__) 
 284   #if (BOOTLOADER_ADDRESS != 0x7000) 
 285     #error BOOTLOADER_ADDRESS!=0x7000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 288   #error undefined device selection - this should not happen!  
 291 //assume  SPMCR==0x37, SPMEN==0x0, RWWSRE=0x4, RWWSB=0x6 
 292 #if HAVE_SPMINTEREFACE_MAGICVALUE 
 293 const uint16_t bootloader__do_spm
[23] BOOTLIBLINK 
= { 
 294   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 24) & 0xf))), // r23 
 295   bootloader__do_spm_magic_exitstrategy(0xf4a1), // brne +20 
 296   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 16) & 0xf))), // r22 
 297   bootloader__do_spm_magic_exitstrategy(0xf491), // brne +18 
 298   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  8) & 0xf))), // r21 
 299   bootloader__do_spm_magic_exitstrategy(0xf481), // brne +16 
 300   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  0) & 0xf))), // r20 
 301   bootloader__do_spm_magic_exitstrategy(0xf471), // brne +14 
 303 const uint16_t bootloader__do_spm
[15] BOOTLIBLINK 
= { 
 305   0x2dec, 0x2dfd, 0xb6b7, 0xfcb0, 0xcffd, 0xbf27, 0x95e8, 0xb6b7, 
 306   0xfcb0, 0xcffd, 0xe121, 0xb6b7, 0xfcb6, 0xcff4, 0x9508 
 310 00001826 <bootloader__do_spm>: 
 311     1828:       ec 2d           mov     r30, r12 
 312     182a:       fd 2d           mov     r31, r13 
 315     182c:       b7 b6           in      r11, 0x37       ; 55 
 316     182e:       b0 fc           sbrc    r11, 0 
 317     1830:       fd cf           rjmp    .-6             ; 0x182c <waitA> 
 318     1832:       27 bf           out     0x37, r18       ; 55 
 322     1836:       b7 b6           in      r11, 0x37       ; 55 
 323     1838:       b0 fc           sbrc    r11, 0 
 324     183a:       fd cf           rjmp    .-6             ; 0x1836 <waitB> 
 325     183c:       21 e1           ldi     r18, 0x11       ; 17 
 326     183e:       b7 b6           in      r11, 0x37       ; 55 
 327     1840:       b6 fc           sbrc    r11, 6 
 328     1842:       f4 cf           rjmp    .-24            ; 0x182c <waitA> 
 336 #elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48P__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__) || defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) 
 338 #if defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__) 
 339   #if (BOOTLOADER_ADDRESS != 0x1800) 
 340     #error BOOTLOADER_ADDRESS!=0x1800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 342 #elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) 
 343   #if (BOOTLOADER_ADDRESS != 0x3800) 
 344     #error BOOTLOADER_ADDRESS!=0x3800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 347   #error undefined device selection - this should not happen!  
 350 //assume  SPMCR:=SPMCSR==0x37, SPMEN:=SELFPRGEN==0x0, RWWSRE=0x4, RWWSB=0x6 
 351 #if HAVE_SPMINTEREFACE_MAGICVALUE 
 352 const uint16_t bootloader__do_spm
[23] BOOTLIBLINK 
= { 
 353   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 24) & 0xf))), // r23 
 354   bootloader__do_spm_magic_exitstrategy(0xf4a1), // brne +20 
 355   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 16) & 0xf))), // r22 
 356   bootloader__do_spm_magic_exitstrategy(0xf491), // brne +18 
 357   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  8) & 0xf))), // r21 
 358   bootloader__do_spm_magic_exitstrategy(0xf481), // brne +16 
 359   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  0) & 0xf))), // r20 
 360   bootloader__do_spm_magic_exitstrategy(0xf471), // brne +14 
 362 const uint16_t bootloader__do_spm
[15] BOOTLIBLINK 
= { 
 364   0x2dec, 0x2dfd, 0xb6b7, 0xfcb0, 0xcffd, 0xbf27, 0x95e8, 0xb6b7, 
 365   0xfcb0, 0xcffd, 0xe121, 0xb6b7, 0xfcb6, 0xcff4, 0x9508 
 368 00001826 <bootloader__do_spm>: 
 369     1828:       ec 2d           mov     r30, r12 
 370     182a:       fd 2d           mov     r31, r13 
 373     182c:       b7 b6           in      r11, 0x37       ; 55 
 374     182e:       b0 fc           sbrc    r11, 0 
 375     1830:       fd cf           rjmp    .-6             ; 0x182c <waitA> 
 376     1832:       27 bf           out     0x37, r18       ; 55 
 380     1836:       b7 b6           in      r11, 0x37       ; 55 
 381     1838:       b0 fc           sbrc    r11, 0 
 382     183a:       fd cf           rjmp    .-6             ; 0x1836 <waitB> 
 383     183c:       21 e1           ldi     r18, 0x11       ; 17 
 384     183e:       b7 b6           in      r11, 0x37       ; 55 
 385     1840:       b6 fc           sbrc    r11, 6 
 386     1842:       f4 cf           rjmp    .-24            ; 0x182c <waitA> 
 394 #elif defined (__AVR_ATmega48A__) || defined (__AVR_ATmega48PA__) || defined (__AVR_ATmega88A__) || defined (__AVR_ATmega88PA__) || defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168PA__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) 
 396 #if defined (__AVR_ATmega88A__) || defined (__AVR_ATmega88PA__) 
 397   #if (BOOTLOADER_ADDRESS != 0x1800) 
 398     #error BOOTLOADER_ADDRESS!=0x1800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 400 #elif defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168PA__) 
 401   #if (BOOTLOADER_ADDRESS != 0x3800) 
 402     #error BOOTLOADER_ADDRESS!=0x3800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 404 #elif defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) 
 405   #if (BOOTLOADER_ADDRESS != 0x7000) 
 406     #error BOOTLOADER_ADDRESS!=0x7000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 409   #error undefined device selection - this should not happen!  
 412 //assume  SPMCR:=SPMCSR==0x37, SPMEN:=SELFPRGEN==0x0, RWWSRE=0x4, RWWSB=0x6 
 413 #if HAVE_SPMINTEREFACE_MAGICVALUE 
 414 const uint16_t bootloader__do_spm
[23] BOOTLIBLINK 
= { 
 415   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 24) & 0xf))), // r23 
 416   bootloader__do_spm_magic_exitstrategy(0xf4a1), // brne +20 
 417   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 16) & 0xf))), // r22 
 418   bootloader__do_spm_magic_exitstrategy(0xf491), // brne +18 
 419   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  8) & 0xf))), // r21 
 420   bootloader__do_spm_magic_exitstrategy(0xf481), // brne +16 
 421   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  0) & 0xf))), // r20 
 422   bootloader__do_spm_magic_exitstrategy(0xf471), // brne +14 
 424 const uint16_t bootloader__do_spm
[15] BOOTLIBLINK 
= { 
 426   0x2dec, 0x2dfd, 0xb6b7, 0xfcb0, 0xcffd, 0xbf27, 0x95e8, 0xb6b7, 
 427   0xfcb0, 0xcffd, 0xe121, 0xb6b7, 0xfcb6, 0xcff4, 0x9508 
 430 00001826 <bootloader__do_spm>: 
 431     1828:       ec 2d           mov     r30, r12 
 432     182a:       fd 2d           mov     r31, r13 
 435     182c:       b7 b6           in      r11, 0x37       ; 55 
 436     182e:       b0 fc           sbrc    r11, 0 
 437     1830:       fd cf           rjmp    .-6             ; 0x182c <waitA> 
 438     1832:       27 bf           out     0x37, r18       ; 55 
 442     1836:       b7 b6           in      r11, 0x37       ; 55 
 443     1838:       b0 fc           sbrc    r11, 0 
 444     183a:       fd cf           rjmp    .-6             ; 0x1836 <waitB> 
 445     183c:       21 e1           ldi     r18, 0x11       ; 17 
 446     183e:       b7 b6           in      r11, 0x37       ; 55 
 447     1840:       b6 fc           sbrc    r11, 6 
 448     1842:       f4 cf           rjmp    .-24            ; 0x182c <waitA> 
 456 #elif defined (__AVR_ATmega128__) 
 458 #if defined (__AVR_ATmega128__) 
 459   #if (BOOTLOADER_ADDRESS != 0x1E000) 
 460     #error BOOTLOADER_ADDRESS!=0x1E000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 463   #error undefined device selection - this should not happen!  
 466 //assume  SPMCR:=SPMCSR==0x68, SPMEN==0x0, RWWSRE=0x4, RWWSB=0x6 and rampZ=0x3b 
 467 #if HAVE_SPMINTEREFACE_MAGICVALUE 
 468 const uint16_t bootloader__do_spm
[28] BOOTLIBLINK 
= { 
 469   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 24) & 0xf))), // r23 
 470   bootloader__do_spm_magic_exitstrategy(0xf4c9), // brne +21+4 
 471   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 16) & 0xf))), // r22 
 472   bootloader__do_spm_magic_exitstrategy(0xf4b9), // brne +19+4 
 473   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  8) & 0xf))), // r21 
 474   bootloader__do_spm_magic_exitstrategy(0xf4a9), // brne +17+4 
 475   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  0) & 0xf))), // r20 
 476   bootloader__do_spm_magic_exitstrategy(0xf499), // brne +15+4 
 478 const uint16_t bootloader__do_spm
[20] BOOTLIBLINK 
= { 
 480   0xbebb, 0x2dec, 0x2dfd, 0x90b0, 0x0068, 0xfcb0, 0xcffc, 0x9320, 0x0068, 
 481   0x95e8, 0x90b0, 0x0068, 0xfcb0, 0xcffc, 0xe121, 0x90b0, 0x0068, 0xfcb6, 
 485 0001e08c <bootloader__do_spm>: 
 486    1e08c:       bb be           out     0x3b, r11       ; 59 
 487    1e08e:       ec 2d           mov     r30, r12 
 488    1e090:       fd 2d           mov     r31, r13 
 491    1e092:       b0 90 68 00     lds     r11, 0x0068 
 492    1e096:       b0 fc           sbrc    r11, 0 
 493    1e098:       fc cf           rjmp    .-8             ; 0x1e092 <waitA> 
 494    1e09a:       20 93 68 00     sts     0x0068, r18 
 498    1e0a0:       b0 90 68 00     lds     r11, 0x0068 
 499    1e0a4:       b0 fc           sbrc    r11, 0 
 500    1e0a6:       fc cf           rjmp    .-8             ; 0x1e0a0 <waitB> 
 501    1e0a8:       21 e1           ldi     r18, 0x11       ; 17 
 502    1e0aa:       b0 90 68 00     lds     r11, 0x0068 
 503    1e0ae:       b6 fc           sbrc    r11, 6 
 504    1e0b0:       f0 cf           rjmp    .-32            ; 0x1e092 <waitA> 
 512 #elif defined (__AVR_ATmega164A__) || defined (__AVR_ATmega164P__) || defined (__AVR_ATmega164PA__) || defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__) || defined (__AVR_ATmega324PA__) || defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) || defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__) 
 514 #if defined (__AVR_ATmega164A__) || defined (__AVR_ATmega164P__) || defined (__AVR_ATmega164PA__) 
 515   #if (BOOTLOADER_ADDRESS != 0x3800) 
 516     #error BOOTLOADER_ADDRESS!=0x3800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 518 #elif defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__) || defined (__AVR_ATmega324PA__) 
 519   #if (BOOTLOADER_ADDRESS != 0x7000) 
 520     #error BOOTLOADER_ADDRESS!=0x7000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 522 #elif defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) 
 523   #if (BOOTLOADER_ADDRESS != 0xE000) 
 524     #error BOOTLOADER_ADDRESS!=0xE000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 526 #elif defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__) 
 527   #if (BOOTLOADER_ADDRESS != 0x1E000) 
 528     #error BOOTLOADER_ADDRESS!=0x1E000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use 
 531   #error undefined device selection - this should not happen!  
 534 //assume  SPMCR:=SPCSR==0x37, SPMEN==0x0, RWWSRE=0x4, RWWSB=0x6 and rampZ=0x3b 
 535 #if HAVE_SPMINTEREFACE_MAGICVALUE 
 536 const uint16_t bootloader__do_spm
[24] BOOTLIBLINK 
= { 
 537   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 24) & 0xf))), // r23 
 538   bootloader__do_spm_magic_exitstrategy(0xf4a9), // brne +21 
 539   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 16) & 0xf))), // r22 
 540   bootloader__do_spm_magic_exitstrategy(0xf499), // brne +19 
 541   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  8) & 0xf))), // r21 
 542   bootloader__do_spm_magic_exitstrategy(0xf489), // brne +17 
 543   (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE 
>>  0) & 0xf))), // r20 
 544   bootloader__do_spm_magic_exitstrategy(0xf479), // brne +15 
 546 const uint16_t bootloader__do_spm
[16] BOOTLIBLINK 
= { 
 549   0x2dec, 0x2dfd, 0xb6b7, 0xfcb0, 0xcffd, 0xbf27, 0x95e8, 0xb6b7, 
 550   0xfcb0, 0xcffd, 0xe121, 0xb6b7, 0xfcb6, 0xcff4, 0x9508 
 553 00001826 <bootloader__do_spm>: 
 554     1826:       bb be           out     0x3b,r11        ; rampZ=r11; (rampZ is at IO 0x3b) 
 555     1828:       ec 2d           mov     r30, r12 
 556     182a:       fd 2d           mov     r31, r13 
 559     182c:       b7 b6           in      r11, 0x37       ; 55 
 560     182e:       b0 fc           sbrc    r11, 0 
 561     1830:       fd cf           rjmp    .-6             ; 0x182c <waitA> 
 562     1832:       27 bf           out     0x37, r18       ; 55 
 566     1836:       b7 b6           in      r11, 0x37       ; 55 
 567     1838:       b0 fc           sbrc    r11, 0 
 568     183a:       fd cf           rjmp    .-6             ; 0x1836 <waitB> 
 569     183c:       21 e1           ldi     r18, 0x11       ; 17 
 570     183e:       b7 b6           in      r11, 0x37       ; 55 
 571     1840:       b6 fc           sbrc    r11, 6 
 572     1842:       f4 cf           rjmp    .-24            ; 0x182c <waitA> 
 581   #error "bootloader__do_spm has to be adapted, since there is no architecture code, yet"