[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[avr-libc-dev] RFC: avr/bits.h
From: |
Erik Walthinsen |
Subject: |
[avr-libc-dev] RFC: avr/bits.h |
Date: |
Tue, 01 Mar 2005 01:15:47 -0800 |
User-agent: |
Debian Thunderbird 1.0 (X11/20050116) |
As per E. Weddinton's suggestion a month ago, I'd like to start the
process of getting avr/bits.h included in avr-libc. A first pass at the
file and its documentation are attached.
The first macro is BIT(), requested by a number of people as a
replacement for the not-so-obviously-named _BV(), which is nominally an
internal-use-only macro according to its leading underscore.
The bit_[set/clear/toggle/read]() macros all accept a single bit
position, and use the BIT() macro internally. Eric had listed a whole
set of macros for various bit widths, with the un-specified form
referring to the byte-wide versions, but afaict this is not necessary.
Tests I ran against gcc 3.4.3 showed that the compiler does not appear
over-promote constants, so it will produce optimal code as required for
the operand size.
(Mostly: twiddle bits in only one byte of a uint16_t and it loads/stores
both bytes but only modifies one of them. Not sure if this is desirable
or necessary, as per the 16-bit write debate in avr-gcc-list atm.)
The bit_[set/clear/toggle/read]_mask() macros all accept a straight
integer operand that is applied to the register as appropriate. This
allows:
bit_set_mask(PORTB, BIT(2) | BIT(4));
Question: should they be named e.g. bit_set_mask() or bit_mask_set()?
Finally, I've included a gcc-ism (which other compilers will silently
ignore as per the C spec) that "poisons" the old sbi/cbi macros. This
means that if you attempt to compile something that has not been
converted yet, you will get:
test.c:14:3: attempt to use poisoned "sbi"
This IMO is a lot more meaningful and accurate than the usual:
test.c:9: undefined reference to `sbi'
Define AVR_NO_SBI_CBI_POISONING as per the documentation in order to
turn this off and retrofit existing code with "#define sbi bit_set" etc.
Interestingly, the GCC documentation claims that if you place this
#define *before* the "#pragma GCC poison", it's supposed to bypass it.
Well, in 3.4.3 it doesn't, so we have to use an #ifndef instead, which
is probably clearer anyway.
The documentation at the top is a first (rough) pass at explaining when
one can effectively use these macros, and when one should be using
normal C bit-manipulation operations. Some issues, mostly
codesize-related, are not obvious because the AVR's *do* have sbi/cbi to
make certain sequences much smaller, in select cases. This would be the
ideal place to explain them once and for all.
It's far too rough for me right now, but I want to hear others' comments
on it before doing a second pass. I haven't used doxygen before either
(used gtk-doc extensively, but it's totally different), so I'm sure the
docs could be organized better.
Comments, enhancements, and additional documentation requested. Let's
get this finished and the sbi/cbi mess behind us.
TIA,
Omega
aka Erik Walthinsen
address@hidden
/* Copyright (c) 2005 Erik Walthinsen
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
/* $Id$ */
/** \defgroup avr_bits Bit-manipulation convenience macros
\code #include <avr/bits.h> \endcode
This header file defines various macros that make certain
bit-fiddling operations more convenient. They operate on single
bits, using the bit-position macros defined for each AVR device in
avr/io.h.
A modern avr-gcc will properly compile many of these macros down to
a single instruction where possible (e.g. sbi/cbi for
bit_set/bit_clear where the byte being fiddled with is in the first
32 registers allowed by sbi/cbi's instruction encoding). This is
useful for single operations, but does not scale when peforming more
than 3 such operations in a row. In such cases you will want to
make use of standard C bit operations:
\code
PORTA |= 0x6a;
\endcode
instead of:
\code
bit_set(PORTA,1);
bit_set(PORTA,3);
bit_set(PORTA,5);
bit_set(PORTA,7);
\endcode
\par Size and Speed
When deciding whether to use macros in this header or native C bit
operations, consider both the size of the resulting code and the
exact behavior required.
The bit_set() and bit_clear() routines each encode to a single
instruction only if they are being used to access one of the first
32 registers in I/O space. Check the datasheet for the device you
are using to see which registers these are.
All other single-bit operations in this header file will encode to a
read/modify/write sequence. This will take 3 instructions when
operating on a volatile variable or register, and may take as few as
one if operation is performed between other code using the variable.
If you are flipping more than one bit at a time, you will need to
take these into consideration, compared with the size of a classic
read/modify/write as constructed from an operation such as:
\code PORTA |= 0x6a; \endcode
which will compile as three instructions or less no matter how many
bits you are setting.
\par Operation Sequencing
Separately written bit operations will result in independent code
sequence for each C statement. This will cause multiple bits
flipped in a sequence to be altered on different clock cycles. If
this is not what you want, you will need to use a read/modify/write
as per the previous example.
\par sbi() and cbi() poisoning
Using a GCC-specific #pragma, the old deprecated macros sbi() and
cbi() have been poisoned, which will throw a compiler error with an
error that is more useful than "undefined reference to..." under the
circumstances.
If you are retrofitting older code that uses these macros, you can
recreate sbi()/cbi() and bypass the poisoning by putting the
following code <b>before</b> you include this header:
\code
#define sbi bit_set
#define cbi bit_clear
#define AVR_NO_SBI_CBI_POISONING
\endcode
*/
#ifndef _AVR_BITS_H_
#define _AVR_BITS_H_
/** \ingroup avr_bits
Construct an integer with a single bit set at position \c bitpos.
*/
#define BIT(bitpos) (1<<(bitpos))
/** \ingroup avr_bits
Set the bit located at position \c bit in variable/register \c var.
*/
#define bit_set(var, bit) ((var) |= BIT(bit))
/** \ingroup avr_bits
Clear the bit located at position \c bit in variable/register \c var.
*/
#define bit_clear(var, bit) ((var) &= ~BIT(bit))
/** \ingroup avr_bits
Toggle the bit located at position \c bit in variable/register \c var.
*/
#define bit_toggle(var, bit) ((var) ^= BIT(bit))
/** \ingroup avr_bits
Read the bit located at position \c bit in variable/register \c var.
*/
#define bit_read(var, bit) ((var) & BIT(bit))
/** \ingroup avr_bits
Set any bits in \c mask in variable/register \c var. */
#define bit_set_mask(var, mask) ((var) |= (mask))
/** \ingroup avr_bits
Clear any bits in \c mask in variable/register \c var. */
#define bit_clear_mask(var, mask) ((var) &= ~(mask))
/** \ingroup avr_bits
Toggle any bits in \c mask in variable/register \c var. */
#define bit_toggle_mask(var, mask) ((var) ^= (mask))
/** \ingroup avr_bits
Read any bits in \c mask in variable/register \c var. */
#define bit_read_mask(var, mask) ((var) & (mask))
/* Deprecated macros, throw a more useful error: */
/** \ingroup avr_bits
Define this macro in order to disable the poisoning of the
deprecated sbi() and cbi() macros.
*/
#ifndef AVR_NO_SBI_CBI_POISONING
#pragma GCC poison sbi cbi
#endif
#endif /* _AVR_BITS_H_ */
- [avr-libc-dev] RFC: avr/bits.h,
Erik Walthinsen <=
Re: [avr-libc-dev] RFC: avr/bits.h, Dave Hylands, 2005/03/01
Re: [avr-libc-dev] RFC: avr/bits.h, Joerg Wunsch, 2005/03/01