avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] What Happened to the sbi() and cbi() Macros????


From: Erik Walthinsen
Subject: Re: [avr-gcc-list] What Happened to the sbi() and cbi() Macros????
Date: Sun, 30 Jan 2005 20:11:11 -0800
User-agent: Debian Thunderbird 1.0 (X11/20050116)

Douglas Dotson wrote:
I guess that the term "deprecated" doesn't ring
true with some. Anyone that disagrees with the
policy can define the deprecated features in their
own local headers. Just because a feature is deprecated doesn't mean it can't be used.

Not a single person here is going to disagree with the definition of deprecated. Everyone is fully aware that the utter absence of such fundamental macros from the fundamental library does not in any way mean they cannot be used.

What is at issue is WHY these particular macros, being probably the most used of the entire avr-libc BY FAR, have been declared to be deprecated and by whom, with what reasoning, discussion, and ultimately recourse.

Consider the difference in definition between "deprecated" and "obsolete", and let's examine whether sbi/cbi are obsolete and therefore should have been deprecated, or are *not* obsolete and therefore should *not* have been deprecated.

I have searched google and not found a single reason why they have been removed, only speculation as to the reasons. Specifically, I find http://www.avr1.org/pipermail/avr-gcc-list/2004-November/008022.html where it is speculated that they have been removed due to dependence on certain hardware in order to execute.

Well, that may have been true back before the compiler was smart enough to use memory-mapped access to registers, where the sbi/cbi macros were literally asm()'s using those instructions directly. Here one immediately runs into the primary issue with sbi/cbi, namely that they can only operate on the first 32 registers / memory locations.

(As for requiring specific hardware, every AVR ever made AFAIK has the sbi/cbi instructions.)

Except now, and for as long as I've been using this stuff (admittedly not all that long), the compiler really is smart. Not only can it generate sbi/cbi instructions where appropriate (which seems to be the cool feature that's touted when claiming that sbi/cbi are obsolete), but it is so smart that the definition of _SFR_BYTE has been irrevocably changed:

#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define _SFR_MEM_ADDR(sfr) (sfr)
#define _SFR_ADDR(sfr) _SFR_MEM_ADDR(sfr)
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))

There are no #ifdefs or any other conditionals, _SFR_BYTE will *always* access a memory location. This means that sbi/cbi expand thusly:

sbi(PORTA,4);
  vvvvv
#define sbi (sfr,bit) (_SFR_BYTE(sfr) |= _BV(bit))
  vvvvv
(_SFR_BYTE(PORTA) |= _BV(4));
  vvvvv
(_MMIO_BYTE(_SFR_ADDR(PORTA)) |= (1<<4));
  vvvvv
((*(volatile uint8_t *)(_SFR_ADDR(PORTA))) |= 0x10));
  vvvvv
((*(volatile uint8_t *)(_SFR_MEM_ADDR(PORTA))) |= 0x10));
  vvvvv
((*(volatile uint8_t *)(PORTA)) |= 0x10));

And because of this magic memory-mapped access capability, this is identical to:

PORTA |= 0x10;

Therefore the proper definition of sbi is nominally (and is in my newly created "deprecated.h") the following:

#define sbi (sfr,bit) (sfr |= _BV(bit))

I am unaware of any reason why in any situation, given the newfound intelligence of the compiler, where this new definition would fail to work. In fact, I know for a fact it will handle rather sophisticated programs, because I just compiled my most complicated program. Or rather, I tried to and failed, but got no errors related to sfrs. Instead I get errors related to the newly missing twi.h, which I was unaware was gone until now. It conveniently removed every last one of the TW_* #defines, which are required to sanely implement 2-wire.

Great, more deprecated macros that I'll now have to dig through all my programs and replace with..... <drumroll> hex values that mean nothing whatsoever without flipping through the PDF of the datasheet to determine which magic value is which of the *28* result codes from the TWI subsystem.

Someone please tell me that I'm just on the wrong planet, and the act of removing all these macros makes perfect sense, because we're all supposed to write programs that look like this:

  // send the i2c address
  TWDR = i2caddr & 0xfe;
  TWCR |= (1<<TWINT);
  do {
  } while (!TWCR & (1<<TWINT));
  switch (TWSR) {
    case 0x18: return 0;
    case 0x20:
    case 0x38: goto restart;
    default: return -(0x0200|TWSR);
  }

instead of this:

  // send the i2c address
  TWDR = i2caddr & 0xfe;
  sbi(TWCR,TWINT);
  loop_until_bit_is_set(TWCR,TWINT);
  switch (TWSR) {
    case TW_MT_SLA_ACK: return 0;
    case TW_MT_SLA_NACK:
    case TW_MT_ARB_LOST: goto restart;
    default: return -(0x0200|TWSR);
  }

All those pesky macros that make code easy to read and write (in that order of importance) are just a waste of time and are being lined up and shot one at a time. Viva la revolution!

The only theory I can come up with as to why the sbi/cbi macros were removed is that the above analysis was not done, and someone looked at the presence of _SFR_BYTE in the macro and decided that it was only going to work for 0<= SFR < 32. Naturally, anything that only works in some cases, on a non-obvious subset of all registers, should be *obsoleted* in favor of better methods (e.g. compiler being smart with instruction generation).

What seems to be ignored is the fact that sbi/cbi, even as they used to be defined, work properly in all cases, and therefore are most definitely not *obsolete*, especially given their *EXTREME* prevalence in everyone's code.

What *is* obsolete is the use of the _SFR_BYTE macro itself. As the goal of deprecation is to remove unwanted cruft (*usually* while retaining the useful stuff that everyone uses), the proper action should have been to redefine sbi/cbi to reflect the new compiler capabilities.

A counter-example, showing where the terms "obsolete" and "deprecated" seem to have been applied properly, is the removal of inp/outp/etc. As a result of this same trend towards a smarter compiler and memory-mapped access to all registers, these functions are totally and utterly *OBSOLETE*. Therefore, they were marked *DEPRECATED* in the 1.0.x series of avr-libc, and properly removed from 1.2.x.

If anyone had gone about writing a program any time since avr-gcc was made smarter making any kind of use of inp/outp/etc., they would (properly IMO) have been laughed at and told to fix their code. *That* is a proper usage of the two terms in question.

Still, I'd love to hear from the horse's mouth (whoever that is) what the logic was behind this move. Haven't a clue myself.

TTYL,
    Omega
    aka Erik Walthinsen
    address@hidden


reply via email to

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