RTEMS CPU Kit with SuperCore  4.11.3
asm.h
Go to the documentation of this file.
1 
17 /*
18  * COPYRIGHT:
19  *
20  * This file is based on similar code found in newlib available
21  * from ftp.cygnus.com. The file which was used had no copyright
22  * notice. This file is freely distributable as long as the source
23  * of the file is noted. This file is:
24  *
25  * COPYRIGHT (c) 1994-1997.
26  * On-Line Applications Research Corporation (OAR).
27  */
28 
29 #ifndef _RTEMS_ASM_H
30 #define _RTEMS_ASM_H
31 
32 /*
33  * Indicate we are in an assembly file and get the basic CPU definitions.
34  */
35 
36 #ifndef ASM
37 #define ASM
38 #endif
39 #include <rtems/score/cpuopts.h>
40 #include <rtems/score/avr.h>
41 
42 /*
43  * Recent versions of GNU cpp define variables which indicate the
44  * need for underscores and percents. If not using GNU cpp or
45  * the version does not support this, then you will obviously
46  * have to define these as appropriate.
47  */
48 
49 #ifndef __USER_LABEL_PREFIX__
50 #define __USER_LABEL_PREFIX__ _
51 #endif
52 
53 #ifndef __REGISTER_PREFIX__
54 #define __REGISTER_PREFIX__
55 #endif
56 
57 #include <rtems/concat.h>
58 
59 /* Use the right prefix for global labels. */
60 
61 #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
62 
63 /* Use the right prefix for registers. */
64 
65 #define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
66 
67 /*
68  * define macros for all of the registers on this CPU
69  *
70  * EXAMPLE: #define d0 REG (d0)
71  */
72 
73 
74 /*
75  * Define macros to handle section beginning and ends.
76  */
77 
78 
79 #define BEGIN_CODE_DCL .text
80 #define END_CODE_DCL
81 #define BEGIN_DATA_DCL .data
82 #define END_DATA_DCL
83 #define BEGIN_CODE .text
84 #define END_CODE
85 #define BEGIN_DATA
86 #define END_DATA
87 #define BEGIN_BSS
88 #define END_BSS
89 #define END
90 
91 /*
92  * Following must be tailor for a particular flavor of the C compiler.
93  * They may need to put underscores in front of the symbols.
94  */
95 
96 #define PUBLIC(sym) .globl SYM (sym)
97 #define EXTERN(sym) .globl SYM (sym)
98 
99 /* Copyright (c) 2002, 2005, 2006, 2007 Marek Michalkiewicz
100  Copyright (c) 2006 Dmitry Xmelkov
101  All rights reserved.
102 
103  Redistribution and use in source and binary forms, with or without
104  modification, are permitted provided that the following conditions are met:
105 
106  * Redistributions of source code must retain the above copyright
107  notice, this list of conditions and the following disclaimer.
108 
109  * Redistributions in binary form must reproduce the above copyright
110  notice, this list of conditions and the following disclaimer in
111  the documentation and/or other materials provided with the
112  distribution.
113 
114  * Neither the name of the copyright holders nor the names of
115  contributors may be used to endorse or promote products derived
116  from this software without specific prior written permission.
117 
118  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
119  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
120  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
121  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
122  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
123  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
124  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
125  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
126  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
127  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
128  POSSIBILITY OF SUCH DAMAGE. */
129 
130 /*
131  macros.inc - macros for use in assembler sources
132 
133  Contributors:
134  Created by Marek Michalkiewicz <marekm@linux.org.pl>
135  */
136 
137 #include <avr/common.h>
138 
139 /* if not defined, assume old version with underscores */
140 #ifndef __USER_LABEL_PREFIX__
141 #define __USER_LABEL_PREFIX__ _
142 #endif
143 
144 #ifndef __REGISTER_PREFIX__
145 #define __REGISTER_PREFIX__
146 #endif
147 
148 /* the assembler line separator (just in case it ever changes) */
149 #define _L $
150 
151 #define CONCAT1(a, b) CONCAT2(a, b)
152 #define CONCAT2(a, b) a ## b
153 
154 #define _U(x) CONCAT1(__USER_LABEL_PREFIX__, x)
155 
156 #define _R(x) CONCAT1(__REGISTER_PREFIX__, x)
157 
158 /* these should help to fix the "can't have function named r1()" bug
159  which may require adding '%' in front of register names. */
160 
161 #define r0 _R(r0)
162 #define r1 _R(r1)
163 #define r2 _R(r2)
164 #define r3 _R(r3)
165 #define r4 _R(r4)
166 #define r5 _R(r5)
167 #define r6 _R(r6)
168 #define r7 _R(r7)
169 #define r8 _R(r8)
170 #define r9 _R(r9)
171 #define r10 _R(r10)
172 #define r11 _R(r11)
173 #define r12 _R(r12)
174 #define r13 _R(r13)
175 #define r14 _R(r14)
176 #define r15 _R(r15)
177 #define r16 _R(r16)
178 #define r17 _R(r17)
179 #define r18 _R(r18)
180 #define r19 _R(r19)
181 #define r20 _R(r20)
182 #define r21 _R(r21)
183 #define r22 _R(r22)
184 #define r23 _R(r23)
185 #define r24 _R(r24)
186 #define r25 _R(r25)
187 #define r26 _R(r26)
188 #define r27 _R(r27)
189 #define r28 _R(r28)
190 #define r29 _R(r29)
191 #define r30 _R(r30)
192 #define r31 _R(r31)
193 
194 #ifndef __tmp_reg__
195 #define __tmp_reg__ r0
196 #endif
197 
198 #ifndef __zero_reg__
199 #define __zero_reg__ r1
200 #endif
201 
202 #if __AVR_MEGA__
203  #define XJMP jmp
204  #define XCALL call
205 #else
206  #define XJMP rjmp
207  #define XCALL rcall
208 #endif
209 
210 /* used only by fplib/strtod.S - libgcc internal function calls */
211 #define PROLOGUE_SAVES(offset) XJMP (__prologue_saves__ + 2 * (offset))
212 #define EPILOGUE_RESTORES(offset) XJMP (__epilogue_restores__ + 2 * (offset))
213 
214 #if FLASHEND > 0x10000 /* ATmega103 */
215  #define BIG_CODE 1
216 #else
217  #define BIG_CODE 0
218 #endif
219 
220 #ifndef __AVR_HAVE_MOVW__
221 # if defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
222 # define __AVR_HAVE_MOVW__ 1
223 # endif
224 #endif
225 
226 #ifndef __AVR_HAVE_LPMX__
227 # if defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
228 # define __AVR_HAVE_LPMX__ 1
229 # endif
230 #endif
231 
232 #ifndef __AVR_HAVE_MUL__
233 # if defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
234 # define __AVR_HAVE_MUL__ 1
235 # endif
236 #endif
237 
238 /*
239  Smart version of movw:
240  - uses "movw" if possible (supported by MCU, and both registers even)
241  - handles overlapping register pairs correctly
242  - no instruction generated if source and destination are the same
243  (may expand to 0, 1 or 2 instructions).
244  */
245 
246 .macro X_movw dst src
247  .L_movw_dst = -1
248  .L_movw_src = -1
249  .L_movw_n = 0
250  .irp reg, r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, \
251  r10,r11,r12,r13,r14,r15,r16,r17,r18,r19, \
252  r20,r21,r22,r23,r24,r25,r26,r27,r28,r29, \
253  r30,r31
254  .ifc \reg,\dst
255  .L_movw_dst = .L_movw_n
256  .endif
257  .ifc \reg,\src
258  .L_movw_src = .L_movw_n
259  .endif
260  .L_movw_n = .L_movw_n + 1
261  .endr
262  .L_movw_n = 0
263  .irp reg, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, \
264  R10,R11,R12,R13,R14,R15,R16,R17,R18,R19, \
265  R20,R21,R22,R23,R24,R25,R26,R27,R28,R29, \
266  R30,R31
267  .ifc \reg,\dst
268  .L_movw_dst = .L_movw_n
269  .endif
270  .ifc \reg,\src
271  .L_movw_src = .L_movw_n
272  .endif
273  .L_movw_n = .L_movw_n + 1
274  .endr
275  .if .L_movw_dst < 0
276  .L_movw_n = 0
277  .rept 32
278  .if \dst == .L_movw_n
279  .L_movw_dst = .L_movw_n
280  .endif
281  .L_movw_n = .L_movw_n + 1
282  .endr
283  .endif
284  .if .L_movw_src < 0
285  .L_movw_n = 0
286  .rept 32
287  .if \src == .L_movw_n
288  .L_movw_src = .L_movw_n
289  .endif
290  .L_movw_n = .L_movw_n + 1
291  .endr
292  .endif
293  .if (.L_movw_dst < 0) || (.L_movw_src < 0)
294  .err ; Invalid 'X_movw' arg.
295  .endif
296 
297  .if ((.L_movw_src) - (.L_movw_dst)) /* different registers */
298  .if (((.L_movw_src) | (.L_movw_dst)) & 0x01)
299  .if (((.L_movw_src)-(.L_movw_dst)) & 0x80) /* src < dest */
300  mov (.L_movw_dst)+1, (.L_movw_src)+1
301  mov (.L_movw_dst), (.L_movw_src)
302  .else /* src > dest */
303  mov (.L_movw_dst), (.L_movw_src)
304  mov (.L_movw_dst)+1, (.L_movw_src)+1
305  .endif
306  .else /* both even -> overlap not possible */
307 #if defined(__AVR_HAVE_MOVW__) && __AVR_HAVE_MOVW__
308  movw \dst, \src
309 #else
310  mov (.L_movw_dst), (.L_movw_src)
311  mov (.L_movw_dst)+1, (.L_movw_src)+1
312 #endif
313  .endif
314  .endif
315 .endm
316 
317 /* Macro 'X_lpm' extends enhanced lpm instruction for classic chips.
318  Usage:
319  X_lpm reg, dst
320  where
321  reg is 0..31, r0..r31 or R0..R31
322  dst is z, Z, z+ or Z+
323  It is possible to omit both arguments.
324 
325  Possible results for classic chips:
326  lpm
327  lpm / mov Rd,r0
328  lpm / adiw ZL,1
329  lpm / mov Rd,r0 / adiw ZL,1
330 
331  For enhanced chips it is one instruction always.
332 
333  ATTENTION: unlike enhanced chips SREG (S,V,N,Z,C) flags are
334  changed in case of 'Z+' dst. R0 is scratch.
335  */
336 .macro X_lpm dst=r0, src=Z
337 
338  /* dst evaluation */
339  .L_lpm_dst = -1
340 
341  .L_lpm_n = 0
342  .irp reg, r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, \
343  r10,r11,r12,r13,r14,r15,r16,r17,r18,r19, \
344  r20,r21,r22,r23,r24,r25,r26,r27,r28,r29, \
345  r30,r31
346  .ifc \reg,\dst
347  .L_lpm_dst = .L_lpm_n
348  .endif
349  .L_lpm_n = .L_lpm_n + 1
350  .endr
351 
352  .L_lpm_n = 0
353  .irp reg, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, \
354  R10,R11,R12,R13,R14,R15,R16,R17,R18,R19, \
355  R20,R21,R22,R23,R24,R25,R26,R27,R28,R29, \
356  R30,R31
357  .ifc \reg,\dst
358  .L_lpm_dst = .L_lpm_n
359  .endif
360  .L_lpm_n = .L_lpm_n + 1
361  .endr
362 
363  .if .L_lpm_dst < 0
364  .L_lpm_n = 0
365  .rept 32
366  .if \dst == .L_lpm_n
367  .L_lpm_dst = .L_lpm_n
368  .endif
369  .L_lpm_n = .L_lpm_n + 1
370  .endr
371  .endif
372 
373  .if (.L_lpm_dst < 0)
374  .err ; Invalid dst arg of 'X_lpm' macro.
375  .endif
376 
377  /* src evaluation */
378  .L_lpm_src = -1
379  .L_lpm_n = 0
380  .irp reg, z,Z,z+,Z+
381  .ifc \reg,\src
382  .L_lpm_src = .L_lpm_n
383  .endif
384  .L_lpm_n = .L_lpm_n + 1
385  .endr
386 
387  .if (.L_lpm_src < 0)
388  .err ; Invalid src arg of 'X_lpm' macro.
389  .endif
390 
391  /* instruction(s) */
392  .if .L_lpm_src < 2
393  .if .L_lpm_dst == 0
394  lpm
395  .else
396 #if defined(__AVR_HAVE_LPMX__) && __AVR_HAVE_LPMX__
397  lpm .L_lpm_dst, Z
398 #else
399  lpm
400  mov .L_lpm_dst, r0
401 #endif
402  .endif
403  .else
404  .if (.L_lpm_dst >= 30)
405  .err ; Registers 30 and 31 are inhibited as 'X_lpm *,Z+' dst.
406  .endif
407 #if defined(__AVR_HAVE_LPMX__) && __AVR_HAVE_LPMX__
408  lpm .L_lpm_dst, Z+
409 #else
410  lpm
411  .if .L_lpm_dst
412  mov .L_lpm_dst, r0
413  .endif
414  adiw r30, 1
415 #endif
416  .endif
417 .endm
418 
419 /*
420  LPM_R0_ZPLUS_INIT is used before the loop to initialize RAMPZ
421  for future devices with RAMPZ:Z auto-increment - [e]lpm r0, Z+.
422 
423  LPM_R0_ZPLUS_NEXT is used inside the loop to load a byte from
424  the program memory at [RAMPZ:]Z to R0, and increment [RAMPZ:]Z.
425 
426  The argument in both macros is a register that contains the
427  high byte (bits 23-16) of the address, bits 15-0 should be in
428  the Z (r31:r30) register. It can be any register except for:
429  r0, r1 (__zero_reg__ - assumed to always contain 0), r30, r31.
430  */
431 
432  .macro LPM_R0_ZPLUS_INIT hhi
433 #if __AVR_ENHANCED__
434  #if BIG_CODE
435  out AVR_RAMPZ_ADDR, \hhi
436  #endif
437 #endif
438  .endm
439 
440  .macro LPM_R0_ZPLUS_NEXT hhi
441 #if __AVR_ENHANCED__
442  #if BIG_CODE
443  /* ELPM with RAMPZ:Z post-increment, load RAMPZ only once */
444  elpm r0, Z+
445  #else
446  /* LPM with Z post-increment, max 64K, no RAMPZ (ATmega83/161/163/32) */
447  lpm r0, Z+
448  #endif
449 #else
450  #if BIG_CODE
451  /* ELPM without post-increment, load RAMPZ each time (ATmega103) */
452  out AVR_RAMPZ_ADDR, \hhi
453  elpm
454  adiw r30,1
455  adc \hhi, __zero_reg__
456  #else
457  /* LPM without post-increment, max 64K, no RAMPZ (AT90S*) */
458  lpm
459  adiw r30,1
460  #endif
461 #endif
462  .endm
463 
464 #endif /* _RTEMS_ASM_H */
Intel AVR Set up Basic CPU Dependency Settings Based on Compiler Settings.
This include file defines ANSI concatenation macros.
Common Symbols and Define Undefined Registers.