What about bringing sbi() and cbi() out of retirement?

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sbi() and cbi() seemed to have been retired
as the compiler added support for using CBI/SBI
instructions from normal C code when constants were used and the ports were in the allowed address range.

However, this leaves a hole on processors that have
ports beyond the reach of CBI/SBI instructions.

So why not restore the sbi() and cbi() functions
and make them functions that are guaranteed to provide atomic access no matter what the port address?

It isn't that big of deal to check the address of the port and if the port is out of range use the ATOMIC macros

i.e:

#define cbi(port, bit)                          \
do {                                            \
        if((int) (&port) < (int)32+32)          \
        {                                       \
                port |= _BV(bit);               \
        }                                       \
        else                                    \
        {                                       \
                ATOMIC_BLOCK(ATOMIC_RESTORESTATE) \
                {                               \
                        port |= _BV(bit);       \
                }                               \
        }                                       \
} while(0)

#define sbi(port, bit)                          \
do {                                            \
        if((int) (&port) < (int)32+32)          \
        {                                       \
                port &= ~_BV(bit);              \
        }                                       \
        else                                    \
        {                                       \
                ATOMIC_BLOCK(ATOMIC_RESTORESTATE) \
                {                               \
                        port &= ~_BV(bit);      \
                }                               \
        }                                       \
} while(0)

--- bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
So why not restore the sbi() and cbi() functions
and make them functions that are guaranteed to provide atomic access no matter what the port address?
Atomic access is not up to the compiler, it is up to you, the programmer. The purpose of sbi/cbi was optimization, not atomicity.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bperrybap wrote:
So why not restore the sbi() and cbi() functions and make them functions that are guaranteed to provide atomic access no matter what the port address?

You need atomic access only seldom and thus no need to waste 3 instructions always. And in interrupts this would waste some additional push/pop.

Atomic access was only needed, if an interrupt set pins of the same port also.

The better approach should be to use pins inside interrupt which are bit accessible. This may also save some push/pop inside the interrupt.

And use the not bit accessible pins only inside the main loop. Then no additional atomic statements needed.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
Atomic access is not up to the compiler, it is up to you, the programmer. The purpose of sbi/cbi was optimization, not atomicity.

Exactly why I am proposing bringing back sbi() and cbi() as library functions (not compiler built-in functions).
It could provide an easy way for people to have guaranteed atomic bit access. Yes the macro example I provided depends on optimization to get SBI/CBI instructions,
but the macro could easily be updated to use in line assembler to force CBI/SBI instructions so that the code generation would not be up to the compiler.

danni wrote:

You need atomic access only seldom and thus no need to waste 3 instructions always. And in interrupts this would waste some additional push/pop.

Atomic access was only needed, if an interrupt set pins of the same port also.

The better approach should be to use pins inside interrupt which are bit accessible. This may also save some push/pop inside the interrupt.

And use the not bit accessible pins only inside the main loop. Then no additional atomic statements needed.

Peter

It is not necessarily true that you only need atomic access seldom.
It very much depends on your hardware configuration and software design.
In the types of real-time embedded projects that I've been involved with over the past 30 years it is needed in nearly every one of them.

The macros/functions that I'm proposing do not blindly added additional instruction overhead. It is only added when necessary to ensure atomic access. If the user picks pins that are within the CBI/SBI range, he gets CBI/SBI instructions with no additional overhead. However, for those cases where for whatever reason, it was necessary to use a pin outside the CBI/SBI range, the user is guaranteed to get atomic access to those pins as well.

What you both are missing is that in certain environments there is not always the luxury of being able to control which pins are used.

Consider a source library that users include in their code. Also consider cases where the users of the library
may actually be unaware which pins are on which ports.
Hard to imagine this?
Well think no further than Arduino.

Having atomic sbi() and cbi() bit setting functions would be a nice addition to the AVR util functions.
There are already functions for delays, eeprom, crcs, baudrate calcuations, etc... Why not a function for guaranteed atomic bit access?

Anyway, I've coded around atomic issues in my library code that can guarantee atomic access and thought it would be very useful to bring back the sbi() and cbi() functions so everyone would not to re-invent the wheel to do this.

--- bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Seconded.

It could be further improved using _builtin_const_p() to check if a constant address is used, and the ATOMIC_BLOCK macro could be improved to avoid redundant code if it is nested.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TimothyEBaldwin wrote:
Seconded.

It could be further improved using _builtin_const_p() to check if a constant address is used, and the ATOMIC_BLOCK macro could be improved to avoid redundant code if it is nested.

I didn't follow the comment on ATOMIC_BLOCK and nesting.

BTW, I just noticed my example macros were wrong, in that the cbi and sbi macros were backwards... :oops:

I had looked at using __builtin_constant_p() and in fact my early version did have it but there are better ways to set bits when not using constants (i.e. pre-calculating a bit mask, etc...)
But here it is

#define sbi(port, bit)                          \
do {                                            \
        if(__builtin_constant_p(&port) && __builtin_constant_p(bit))    \
        {                                       \
                if((int) (&port) < (int)32+32)  \
                {                               \
                        port |= _BV(bit);       \
                }                               \
                else                            \
                {                               \
                        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) \
                        {                       \
                                port |= _BV(bit);\
                        }                       \
                }                               \
        }                                       \
        else                                    \
        {                                       \
                ATOMIC_BLOCK(ATOMIC_RESTORESTATE) \
                {                               \
                        port |= _BV(bit);       \
                }                               \
        }                                       \
} while(0)

#define cbi(port, bit)                          \
do {                                            \
        if(__builtin_constant_p(&port) && __builtin_constant_p(bit))    \
        {                                       \
                if((int) (&port) < (int)32+32)  \
                {                               \
                        port &= ~_BV(bit);      \
                }                               \
                else                            \
                {                               \
                        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) \
                        {                       \
                                port &= ~_BV(bit);\
                        }                       \
                }                               \
        }                                       \
        else                                    \
        {                                       \
                ATOMIC_BLOCK(ATOMIC_RESTORESTATE) \
                {                               \
                        port &= ~_BV(bit);      \
                }                               \
        }                                       \
} while(0)

I guess what I'm assuming is that for the many folks that struggle with bit manipulation, having an atomic set of bit manipulation macros would be useful.

Perhaps atomic versions or interrupt safe versions of the bit manipulation macros in the tutorials, i.e.

atomic_bit_set(p,m)

etc...

--- bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bperrybap wrote:

I guess what I'm assuming is that for the many folks that struggle with bit manipulation

I have a hard time understanding that one would assume that there are many people that struggle with bit manipulation.