Submitted by:  Chris Morse and Don Carveth		Feb. 9, 2002

Chris Morse - crmorse@yahoo.com
Don Carveth - don@botgoodies.com

Proposal

We propose that the GCC AVR standard header files be enhanced to allow the use of direct assignment to I/O register locations, i.e. PORTA = x  or  x = PORTA.  

"Assignment" mode -  allows the use of both direct assignment and macro access "Macro" mode -  access I/O registers by macros only.

A new set of macros is included that maintains compatibility with existing macros and a compiler flag is included to select either the new headers or the existing headers.

Advantages over Macro mode

* More readable, more intuitive code
* Compatibility with the Imagecraft compiler (if direct assignment used)
* Added cbiv, sbiv macros that can accept port and pin variables

Disadvantages

* We have included both the new and original headers and macros and allow the user to select which mode to use.  We expect that Macro mode would be eliminated at some point in the future resulting in a macro file that is simplified compared to the existing file.

What Changes are Required?

* A macro compiler flag is defined (_IO_REG_ASSIGN_MODE_  or  (_IO_REG_MACRO_MODE_) in user code, before the #include <io.h> statement, that selects Assignment mode or Macro mode.  Defaults to assignment mode.
* A macro definition in io-avr.h defines a register label to be defined as either:

#if defined(_IO_REG_ASSIGN_MODE_)  

	#define REGISTER_VAR(x)	(*(volatile uint8_t*)((x)+0x20))
	#define WREGISTER_VAR(x)  (*(volatile uint16_t*)((x)+0x20))

#elif defined(_IO_REG_MACRO_MODE_)
	#define REGISTER_VAR(x)		(x)
	#define WREGISTER_VAR(x)	(x)

#endif

* If Macro mode is defined the current macros are used and the machine dependant header files (io8515.h, etc.) equate to values that are the same as the existing machine dependant header files.
* If Assignment mode is selected then the I/O register labels are defined as above ((*(volatile ... ).  This definition returns the value at the specified register location.
* The machine dependent header file register labels now look like:

#define PORTA     REGISTER_VAR(0x1B)   instead of
#define PORTA   0x1B

* The existing macros will not work with the new I/O register label definitions so a new set of macros was appended to the iomacros.h file.  Either existing or new macros are selected based on the  _IO_REG_ASSIGN_MODE_   or _IO_REG_MACRO_MODE_  flag.

A zip file containing updated io-avr.h, iomacros.h and machine dependent header files based on the Jan. 15, 2002 build is attached.

Compatability

In Assignment mode, all existing macro calls, as defined in the AVR-libc Reference, plus some of the non-listed macros, will function as before.  

In Macro mode everything functions exactly as before.  Assignment method can not be used.

Tested using GCC AVR vs 3.0.2, headers from 01 15 2002 build.

Discussion

The difference in methodology between the two modes was "discovered" while attempting to convert an Imagecraft program to GCC.  After the conversion was complete (and virtually all changes were related to the I/O register access method) it was apparent that Imagecrafts method was a better mousetrap.  Further testing with GCC showed that the compiled results of direct assignment were as good as they were using the I/O macros. 

We were worried that word length assignment would not operate properly but discovered that the GCC compiler understood that an I/O register was being referenced (used in / out instructions) and performed the read or write high/low byte sequence in the correct order.

Pin instructions still require macros.  The original macros were revised to use an assignment mode I/O register label.  Two additional macros were added, sbiv and cbiv, which are comparable to sbi and cbi but can accept variable ports and bits but are slightly slower (3 cycles instead of 2, 3 words instead of 1).

The header files and macros have been tested.

Sample Code from listing file

C program snippets followed by resulting asm code.

These two lines of C code indicate that the compiler uses the efficient in / out instructions for these direct port assignments.

x = PORTA;
in r24,59-0x20

PORTA = x;
out 59-0x20,r24

These two lines of C code show how 16 bit I/O register reads are properly handled by the GCC compiler and the more efficient in / out 
instructions are used
 
y = TCNT1;             /* 16 bit read  */
in r24,76-0x20	     Read low byte
in r25,(76)+1-0x20     Read high byte

TCNT1 = y;             /* 16 bit write */
out (76)+1-0x20,r25    Write high byte
out 76-0x20,r24        Write low byte


Bit Operation Macros

sbi(PORTA, 5);
sbi 27,5

cbi(PORTA, 5);
cbi 27,5


cbiv(PORTA, 1);      /* This takes 3 cycles - a cbi instruction takes 2        cycles  */
in r24,59-0x20
andi r24,lo8(-3)
out 59-0x20,r24

sbiv(PORTA, 2);     /* This  takes 3 cycles - an sbi instruction takes 2 cycles    */
in r24,59-0x20
ori r24,lo8(4)
out 59-0x20,r24

