avr-libc-dev
[Top][All Lists]
Advanced

[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_ */

reply via email to

[Prev in Thread] Current Thread [Next in Thread]