• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

/home/jgoppert/Projects/ap/libraries/FastSerial/macros.inc

Go to the documentation of this file.
00001 /* Copyright (c) 2002, 2005, 2006, 2007 Marek Michalkiewicz
00002    Copyright (c) 2006 Dmitry Xmelkov
00003    All rights reserved.
00004 
00005    Redistribution and use in source and binary forms, with or without
00006    modification, are permitted provided that the following conditions are met:
00007 
00008    * Redistributions of source code must retain the above copyright
00009      notice, this list of conditions and the following disclaimer.
00010 
00011    * Redistributions in binary form must reproduce the above copyright
00012      notice, this list of conditions and the following disclaimer in
00013      the documentation and/or other materials provided with the
00014      distribution.
00015 
00016    * Neither the name of the copyright holders nor the names of
00017      contributors may be used to endorse or promote products derived
00018      from this software without specific prior written permission.
00019 
00020   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00021   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00024   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00030   POSSIBILITY OF SUCH DAMAGE. */
00031 
00032 /*
00033    macros.inc - macros for use in assembler sources
00034 
00035    Contributors:
00036      Created by Marek Michalkiewicz <marekm@linux.org.pl>
00037  */
00038 
00039 #include <avr/io.h>
00040 //#include "sectionname.h"
00041 
00042 /* if not defined, assume old version with underscores */
00043 #ifndef __USER_LABEL_PREFIX__
00044 #define __USER_LABEL_PREFIX__ _
00045 #endif
00046 
00047 #ifndef __REGISTER_PREFIX__
00048 #define __REGISTER_PREFIX__
00049 #endif
00050 
00051 /* the assembler line separator (just in case it ever changes) */
00052 #define _L $
00053 
00054 #define CONCAT1(a, b) CONCAT2(a, b)
00055 #define CONCAT2(a, b) a ## b
00056 
00057 #define _U(x) CONCAT1(__USER_LABEL_PREFIX__, x)
00058 
00059 #define _R(x) CONCAT1(__REGISTER_PREFIX__, x)
00060 
00061 /* these should help to fix the "can't have function named r1()" bug
00062    which may require adding '%' in front of register names.  */
00063 
00064 #define r0 _R(r0)
00065 #define r1 _R(r1)
00066 #define r2 _R(r2)
00067 #define r3 _R(r3)
00068 #define r4 _R(r4)
00069 #define r5 _R(r5)
00070 #define r6 _R(r6)
00071 #define r7 _R(r7)
00072 #define r8 _R(r8)
00073 #define r9 _R(r9)
00074 #define r10 _R(r10)
00075 #define r11 _R(r11)
00076 #define r12 _R(r12)
00077 #define r13 _R(r13)
00078 #define r14 _R(r14)
00079 #define r15 _R(r15)
00080 #define r16 _R(r16)
00081 #define r17 _R(r17)
00082 #define r18 _R(r18)
00083 #define r19 _R(r19)
00084 #define r20 _R(r20)
00085 #define r21 _R(r21)
00086 #define r22 _R(r22)
00087 #define r23 _R(r23)
00088 #define r24 _R(r24)
00089 #define r25 _R(r25)
00090 #define r26 _R(r26)
00091 #define r27 _R(r27)
00092 #define r28 _R(r28)
00093 #define r29 _R(r29)
00094 #define r30 _R(r30)
00095 #define r31 _R(r31)
00096 
00097 #ifndef __tmp_reg__
00098 #define __tmp_reg__ r0
00099 #endif
00100 
00101 #ifndef __zero_reg__
00102 #define __zero_reg__ r1
00103 #endif
00104 
00105 #if __AVR_MEGA__
00106   #define XJMP jmp
00107   #define XCALL call
00108 #else
00109   #define XJMP rjmp
00110   #define XCALL rcall
00111 #endif
00112 
00113 /* used only by fplib/strtod.S - libgcc internal function calls */
00114 #define PROLOGUE_SAVES(offset) XJMP (__prologue_saves__ + 2 * (offset))
00115 #define EPILOGUE_RESTORES(offset) XJMP (__epilogue_restores__ + 2 * (offset))
00116 
00117 #if FLASHEND > 0x10000  /* ATmega103 */
00118   #define BIG_CODE 1
00119 #else
00120   #define BIG_CODE 0
00121 #endif
00122 
00123 #ifndef __AVR_HAVE_MOVW__
00124 #  if  defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
00125 #   define __AVR_HAVE_MOVW__ 1
00126 #  endif
00127 #endif
00128 
00129 #ifndef __AVR_HAVE_LPMX__
00130 # if  defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
00131 #  define __AVR_HAVE_LPMX__ 1
00132 # endif
00133 #endif
00134 
00135 #ifndef __AVR_HAVE_MUL__
00136 # if  defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
00137 #  define __AVR_HAVE_MUL__ 1
00138 # endif
00139 #endif
00140 
00141 /*
00142    Smart version of movw:
00143     - uses "movw" if possible (supported by MCU, and both registers even)
00144     - handles overlapping register pairs correctly
00145     - no instruction generated if source and destination are the same
00146    (may expand to 0, 1 or 2 instructions).
00147  */
00148 
00149 .macro  X_movw dst src
00150         .L_movw_dst = -1
00151         .L_movw_src = -1
00152         .L_movw_n = 0
00153         .irp  reg,      r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, \
00154                         r10,r11,r12,r13,r14,r15,r16,r17,r18,r19, \
00155                         r20,r21,r22,r23,r24,r25,r26,r27,r28,r29, \
00156                         r30,r31
00157                 .ifc  \reg,\dst
00158                         .L_movw_dst = .L_movw_n
00159                 .endif
00160                 .ifc  \reg,\src
00161                         .L_movw_src = .L_movw_n
00162                 .endif
00163                 .L_movw_n = .L_movw_n + 1
00164         .endr
00165         .L_movw_n = 0
00166         .irp  reg,      R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, \
00167                         R10,R11,R12,R13,R14,R15,R16,R17,R18,R19, \
00168                         R20,R21,R22,R23,R24,R25,R26,R27,R28,R29, \
00169                         R30,R31
00170                 .ifc  \reg,\dst
00171                         .L_movw_dst = .L_movw_n
00172                 .endif
00173                 .ifc  \reg,\src
00174                         .L_movw_src = .L_movw_n
00175                 .endif
00176                 .L_movw_n = .L_movw_n + 1
00177         .endr
00178         .if   .L_movw_dst < 0
00179                 .L_movw_n = 0
00180                 .rept   32
00181                         .if \dst == .L_movw_n
00182                                 .L_movw_dst = .L_movw_n
00183                         .endif
00184                         .L_movw_n = .L_movw_n + 1
00185                 .endr
00186         .endif
00187         .if   .L_movw_src < 0
00188                 .L_movw_n = 0
00189                 .rept   32
00190                         .if \src == .L_movw_n
00191                                 .L_movw_src = .L_movw_n
00192                         .endif
00193                         .L_movw_n = .L_movw_n + 1
00194                 .endr
00195         .endif
00196         .if   (.L_movw_dst < 0) || (.L_movw_src < 0)
00197                 .err    ; Invalid 'X_movw' arg.
00198         .endif
00199                 
00200         .if ((.L_movw_src) - (.L_movw_dst))  /* different registers */
00201                 .if (((.L_movw_src) | (.L_movw_dst)) & 0x01)
00202                         .if (((.L_movw_src)-(.L_movw_dst)) & 0x80) /* src < dest */
00203                                 mov     (.L_movw_dst)+1, (.L_movw_src)+1
00204                                 mov     (.L_movw_dst), (.L_movw_src)
00205                         .else                                      /* src > dest */
00206                                 mov     (.L_movw_dst), (.L_movw_src)
00207                                 mov     (.L_movw_dst)+1, (.L_movw_src)+1
00208                         .endif
00209                 .else  /* both even -> overlap not possible */
00210 #if  defined(__AVR_HAVE_MOVW__) && __AVR_HAVE_MOVW__
00211                         movw    \dst, \src
00212 #else
00213                         mov     (.L_movw_dst), (.L_movw_src)
00214                         mov     (.L_movw_dst)+1, (.L_movw_src)+1
00215 #endif
00216                 .endif
00217         .endif
00218 .endm
00219 
00220 /* Macro 'X_lpm' extends enhanced lpm instruction for classic chips.
00221    Usage:
00222         X_lpm   reg, dst
00223    where
00224         reg     is 0..31, r0..r31 or R0..R31
00225         dst     is z, Z, z+ or Z+
00226    It is possible to omit both arguments.
00227 
00228    Possible results for classic chips:
00229         lpm
00230         lpm / mov Rd,r0
00231         lpm / adiw ZL,1
00232         lpm / mov Rd,r0 / adiw ZL,1
00233         
00234    For enhanced chips it is one instruction always.
00235 
00236    ATTENTION:  unlike enhanced chips SREG (S,V,N,Z,C) flags are
00237    changed in case of 'Z+' dst.  R0 is scratch.
00238  */
00239 .macro  X_lpm   dst=r0, src=Z
00240 
00241   /* dst evaluation     */
00242   .L_lpm_dst = -1
00243 
00244   .L_lpm_n = 0
00245   .irp  reg,  r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, \
00246              r10,r11,r12,r13,r14,r15,r16,r17,r18,r19, \
00247              r20,r21,r22,r23,r24,r25,r26,r27,r28,r29, \
00248              r30,r31
00249     .ifc  \reg,\dst
00250       .L_lpm_dst = .L_lpm_n
00251     .endif
00252     .L_lpm_n = .L_lpm_n + 1
00253   .endr
00254 
00255   .L_lpm_n = 0
00256   .irp  reg,  R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, \
00257              R10,R11,R12,R13,R14,R15,R16,R17,R18,R19, \
00258              R20,R21,R22,R23,R24,R25,R26,R27,R28,R29, \
00259              R30,R31
00260     .ifc  \reg,\dst
00261       .L_lpm_dst = .L_lpm_n
00262     .endif
00263     .L_lpm_n = .L_lpm_n + 1
00264   .endr
00265 
00266   .if  .L_lpm_dst < 0
00267     .L_lpm_n = 0
00268     .rept 32
00269       .if  \dst == .L_lpm_n
00270         .L_lpm_dst = .L_lpm_n
00271       .endif
00272       .L_lpm_n = .L_lpm_n + 1
00273     .endr
00274   .endif
00275 
00276   .if  (.L_lpm_dst < 0)
00277     .err        ; Invalid dst arg of 'X_lpm' macro.
00278   .endif
00279 
00280   /* src evaluation     */    
00281   .L_lpm_src = -1
00282   .L_lpm_n = 0
00283   .irp  reg,  z,Z,z+,Z+
00284     .ifc  \reg,\src
00285       .L_lpm_src = .L_lpm_n
00286     .endif
00287     .L_lpm_n = .L_lpm_n + 1
00288   .endr
00289 
00290   .if  (.L_lpm_src < 0)
00291     .err        ; Invalid src arg of 'X_lpm' macro.
00292   .endif
00293 
00294   /* instruction(s)     */    
00295   .if  .L_lpm_src < 2
00296     .if  .L_lpm_dst == 0
00297         lpm
00298     .else
00299 #if  defined(__AVR_HAVE_LPMX__) && __AVR_HAVE_LPMX__
00300         lpm     .L_lpm_dst, Z
00301 #else
00302         lpm
00303         mov     .L_lpm_dst, r0
00304 #endif
00305     .endif
00306   .else
00307     .if  (.L_lpm_dst >= 30)
00308       .err      ; Registers 30 and 31 are inhibited as 'X_lpm *,Z+' dst.
00309     .endif
00310 #if  defined(__AVR_HAVE_LPMX__) && __AVR_HAVE_LPMX__
00311         lpm     .L_lpm_dst, Z+
00312 #else
00313         lpm
00314     .if  .L_lpm_dst
00315         mov     .L_lpm_dst, r0
00316     .endif
00317         adiw    r30, 1
00318 #endif
00319   .endif
00320 .endm
00321 
00322 /*
00323    LPM_R0_ZPLUS_INIT is used before the loop to initialize RAMPZ
00324    for future devices with RAMPZ:Z auto-increment - [e]lpm r0, Z+.
00325 
00326    LPM_R0_ZPLUS_NEXT is used inside the loop to load a byte from
00327    the program memory at [RAMPZ:]Z to R0, and increment [RAMPZ:]Z.
00328 
00329    The argument in both macros is a register that contains the
00330    high byte (bits 23-16) of the address, bits 15-0 should be in
00331    the Z (r31:r30) register.  It can be any register except for:
00332    r0, r1 (__zero_reg__ - assumed to always contain 0), r30, r31.
00333  */
00334 
00335         .macro  LPM_R0_ZPLUS_INIT hhi
00336 #if __AVR_ENHANCED__
00337   #if BIG_CODE
00338         out     AVR_RAMPZ_ADDR, \hhi
00339   #endif
00340 #endif
00341         .endm
00342 
00343         .macro  LPM_R0_ZPLUS_NEXT hhi
00344 #if __AVR_ENHANCED__
00345   #if BIG_CODE
00346     /* ELPM with RAMPZ:Z post-increment, load RAMPZ only once */
00347         elpm    r0, Z+
00348   #else
00349     /* LPM with Z post-increment, max 64K, no RAMPZ (ATmega83/161/163/32) */
00350         lpm     r0, Z+
00351   #endif
00352 #else
00353   #if BIG_CODE
00354     /* ELPM without post-increment, load RAMPZ each time (ATmega103) */
00355         out     AVR_RAMPZ_ADDR, \hhi
00356         elpm
00357         adiw    r30,1
00358         adc     \hhi, __zero_reg__
00359   #else
00360     /* LPM without post-increment, max 64K, no RAMPZ (AT90S*) */
00361         lpm
00362         adiw    r30,1
00363   #endif
00364 #endif
00365         .endm

Generated for ArduPilot Libraries by doxygen