----------------------------------------------------------------------
Patch name: patch.port-to-gcc version 1.1
Author: Bryce Denney <bryce at tlw dot com>
Date: Mon Mar  4 03:22:37 EST 2002

Detailed description:
I have ported Atmel's avr109 code to work with the gcc compiler.
See README.port-to-gcc for details.

To make this patch, I did diff -urN between a clean version and my
working copy, and manually removed any diffs related to CVS (revision 
control files).

Apply patch to:
  avr109.zip from Atmel application note #109
Instructions:
  To patch, unzip the avr109.zip file.
  All the source files land in the current directory.
  Type "patch -p1 < THIS_PATCH_FILE" to apply this patch.
----------------------------------------------------------------------

diff -urN avr109-dist/Makefile avr109-gcc/Makefile
--- avr109-dist/Makefile	Wed Dec 31 19:00:00 1969
+++ avr109-gcc/Makefile	Mon Mar  4 03:15:56 2002
@@ -0,0 +1,27 @@
+#
+# Makefile
+# $Id: patch.port-to-gcc,v 1.5 2002/03/04 08:27:08 bryce Exp $
+#
+# Makefile for building code for Atmel Application Note 109 using gcc.
+#
+
+MCU=atmega163
+CC=avr-gcc
+CFLAGS=-mmcu=$(MCU) -Wa,-ahlms=out.lst -Os -I.
+LFLAGS=-mmcu=$(MCU) -Wl,-Map=out.map  -L.
+all: main
+
+.c.o:
+	$(CC) $(CFLAGS) -c $<
+
+.S.o:
+	$(CC) $(CFLAGS) -c $<
+
+main: main.o serial.o assembly.o main.lcf
+	$(CC) $(LFLAGS) main.o serial.o assembly.o main.lcf -o $@.elf
+	avr-objcopy -O ihex $@.elf $@
+
+clean::
+	rm -f *.o main *.elf out.lst out.map
+
+main.o: main.c defines.h assembly.h
diff -urN avr109-dist/README.gcc avr109-gcc/README.gcc
--- avr109-dist/README.gcc	Wed Dec 31 19:00:00 1969
+++ avr109-gcc/README.gcc	Mon Mar  4 03:18:49 2002
@@ -0,0 +1,67 @@
+README.port-to-gcc
+Patch version 1.0
+Bryce Denney (bryce at tlw dot com)
+
+This file is created when you take the code for Atmel Appnote 109
+and apply my patch.port-to-gcc.  The readme describes the changes included
+in the patch.
+
+The original appnote 109 code can be found at
+  http://www.atmel.com
+  more specifically ftp://www.atmel.com/pub/atmel/avr109.zip
+
+Here's what I did in this patch:
+- enabled ATMEGA163 everywhere, since that's what I can test on.
+- added a Makefile which compiles with avr-gcc.
+- renamed assembly.s90 to assembly.S and hacked it until it worked.
+  - commented out the lines at the top which are not understood by gnu tools:
+    NAME, RSEG, PUBLIC, etc.
+  - changed "DW data" syntax to ".word data" syntax  (e.g. in #define _SPM)
+  - the C function argument passing conventions are clearly different between
+    IAR and gcc.  The original code (intended for IAR) expects the first
+    argument to be in R16/R17, the second argument in R18, etc.  But gcc
+    puts the first argument into R24/R25, then the second argument into
+    R22/R23, etc.  I changed the register numbers in the assembly code so
+    that they would use correct data passed from the C functions.
+- removed cstartup.s90 since avr-gcc creates its own.
+- removed lnk3s.xcl linker file, and created one that gnu tools can understand
+  called main.lcf.  I've never written a linker control file before, so
+  there are probably cleaner ways to do this, but it works.  main.lcf
+  causes the linker to put all the code at word address 0x1e00.  Since the
+  linker uses units of bytes, this translates to byte address 0x3c00.
+- in all C code:
+  - include io.h which defines I/O macros for AVR
+  - change to gcc syntax for I/O reads and writes.  inp(PINC) to read port c,
+    outp (value, PORTC) to write port c.
+- in serial.c, changed recchar() return value type to UNSIGNED char.  If it is
+  treated as signed char, you have big problems in the line in main.c 
+      address=(address<<8)|recchar();
+  Sign extension of recchar() can wipe out all high bits from address<<8.
+
+Version Information:
+These are the packages I am using to compile and test this code.
+- gcc version 3.0 compiled with ./configure --target=avr --enable-languages=c
+- binutils 2.11 compiled with ./configure --target=avr
+- avr-libc 2001-10-29
+- uisp 2001-10-25 in linux, using serial port interface
+
+You will need to set the fuses on your atmega so that it jumps to the
+boot loader.  There is one bit that tells it to jump to the boot loader,
+and a few bits that control the size of the boot loader. 
+
+Results:
+- ATmega163: everything compiles and programming works.  I tested with
+  uisp in Linux, at 2400 baud.
+- ATmega161: won't compile because libc is missing PGERS, SPMEN, PGWRT.
+  On my machine these are missing from the include file 
+  /usr/local/avr/include/iom161.h.  If you are missing them, add 
+  the following lines to defines.h:
+      /* define SPMCR bits for mega161 */
+      #define BLBSET 3
+      #define PGWRT  2
+      #define PGERS  1
+      #define SPMEN  0
+- ATmega32: linker error: unrecognised emulation mode: avr5
+  ???
+- ATmega128: compiler error: MCU `atmega128' not supported
+  ???
diff -urN avr109-dist/assembly.S avr109-gcc/assembly.S
--- avr109-dist/assembly.S	Wed Dec 31 19:00:00 1969
+++ avr109-gcc/assembly.S	Mon Mar  4 03:15:56 2002
@@ -0,0 +1,115 @@
+;	NAME	assembly(16)
+;	RSEG	CODE(0)
+;	RSEG	UDATA0(0)
+;	PUBLIC	fill_temp_buffer
+;	PUBLIC	write_page
+;	PUBLIC	write_lock_bits
+;	PUBLIC  read_program_memory
+;	EXTERN	?CL0T_1_40_L08
+;	RSEG	CODE
+
+#include "defines.h"
+
+#define _SPM    .word 0x95E8      ;Workaround for not having enhanced core Assembler in EWAAVR 2.25
+
+.global	write_page
+write_page:
+        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
+        MOV     R31,R25         
+        MOV     R30,R24     ;move adress to z pointer (R31=ZH R30=ZL)
+#ifdef _ATMEGA104
+        STS     SPMCSR,R22  ;argument 2 decides function
+#else
+        OUT     SPMCR,R22   ;argument 2 decides function
+#endif
+        _SPM                ;Store program memory
+        .word      0xFFFF      ;For future part compatibility, instruction alignment
+        NOP
+        RJMP    WAIT_SPMEN ;Wait for SPMEN flag cleared
+
+.global fill_temp_buffer
+fill_temp_buffer:
+// fixed parameters
+
+        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
+
+        MOV     R31,R23     ;move adress to z pointer (R31=ZH R30=ZL)   
+        MOV     R30,R22     
+        MOV     R1,R25      ;move data to reg 0 and 1      
+        MOV     R0,R24
+ 
+        LDI     R18,(1<<SPMEN)
+        #ifdef _ATMEGA104
+        STS     SPMCSR,R18  ;argument 2 decides function
+        #else
+        OUT     SPMCR,R18   ;argument 2 decides function
+        #endif
+        _SPM                ;Store program memory
+        .word      0xFFFF      ;For future part compatibility, instruction alignment
+        NOP
+        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
+
+.global read_program_memory
+read_program_memory:
+// fix parameter passing
+        RCALL    WAIT_SPMEN
+
+        MOV     R31,R25     ;R31=ZH R30=ZL
+        MOV     R30,R24     ;move adress to z pointer
+        SBRC    R22,0       ;read lockbits? (second argument=0x09)
+                            ;if so, place second argument in SPMEN register
+        #ifdef _ATMEGA104
+        STS     SPMCSR,R22  ;argument 2 decides function
+        #else
+        OUT     SPMCR,R22   ;argument 2 decides function
+        #endif
+        
+        #ifdef LARGE_MEMORY
+	;If large memory (>64K) ELPM is needed to use RAMPZ        
+        ELPM                ;read LSB        
+        #else
+        LPM                 
+        #endif
+
+        MOV     R24,R0      ;read LSB           
+        INC     R30
+
+        #ifdef LARGE_MEMORY //If large memory (>64K) ELPM is needed to use RAMPZ        
+        ELPM                ;read LSB        
+        #else
+        LPM                 
+        #endif
+
+        MOV     R25,R0      ;read MSB (ignored when reading lockbits)
+
+        RET
+
+.global write_lock_bits
+write_lock_bits:
+// fixed parameter passing
+        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
+
+        MOV     R0,R24   
+        LDI     R17,((1<<BLBSET)|(1<<SPMEN))
+
+        #ifdef _ATMEGA104
+        STS     SPMCSR,R17  ;argument 2 decides function
+        #else
+        OUT     SPMCR,R17   ;argument 2 decides function
+        #endif
+
+        _SPM                ;write lockbits
+
+        .word      0xFFFF      ;For future part compatibility, instruction alignment
+        NOP
+        
+        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
+
+WAIT_SPMEN:
+        #ifdef _ATMEGA104
+        LDS     R19,SPMCSR
+        SBRC    R19,SPMEN
+        RJMP    WAIT_SPMEN  ;Wait for SPMEN flag cleared
+        #endif
+        
+        RET
diff -urN avr109-dist/assembly.s90 avr109-gcc/assembly.s90
--- avr109-dist/assembly.s90	Fri Jul 13 12:10:52 2001
+++ avr109-gcc/assembly.s90	Wed Dec 31 19:00:00 1969
@@ -1,109 +0,0 @@
-	NAME	assembly(16)
-	RSEG	CODE(0)
-	RSEG	UDATA0(0)
-	PUBLIC	fill_temp_buffer
-	PUBLIC	write_page
-	PUBLIC	write_lock_bits
-	PUBLIC  read_program_memory
-	EXTERN	?CL0T_1_40_L08
-	RSEG	CODE
-
-#include "defines.h"
-
-#define _SPM    DW 0x95E8      ;Workaround for not having enhanced core Assembler in EWAAVR 2.25
-
-write_page:
-        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
-        MOV     R31,R17         
-        MOV     R30,R16     ;move adress to z pointer (R31=ZH R30=ZL)
-        #ifdef _ATMEGA104
-        STS     SPMCSR,R18  ;argument 2 decides function
-        #else
-        OUT     SPMCR,R18   ;argument 2 decides function
-        #endif
-        _SPM                ;Store program memory
-        DW      0xFFFF      ;For future part compatibility, instruction alignment
-        NOP
-        RJMP    WAIT_SPMEN ;Wait for SPMEN flag cleared
-
-fill_temp_buffer:
-
-        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
-
-        MOV     R31,R19     ;move adress to z pointer (R31=ZH R30=ZL)   
-        MOV     R30,R18     
-        MOV     R1,R17      ;move data to reg 0 and 1      
-        MOV     R0,R16
- 
-        LDI     R18,(1<<SPMEN)
-        #ifdef _ATMEGA104
-        STS     SPMCSR,R18  ;argument 2 decides function
-        #else
-        OUT     SPMCR,R18   ;argument 2 decides function
-        #endif
-        _SPM                ;Store program memory
-        DW      0xFFFF      ;For future part compatibility, instruction alignment
-        NOP
-        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
-
-read_program_memory:
-        RCALL    WAIT_SPMEN
-
-        MOV     R31,R17     ;R31=ZH R30=ZL
-        MOV     R30,R16     ;move adress to z pointer
-        SBRC    R18,0       ;read lockbits? (second argument=0x09)
-                            ;if so, place second argument in SPMEN register
-        #ifdef _ATMEGA104
-        STS     SPMCSR,R18  ;argument 2 decides function
-        #else
-        OUT     SPMCR,R18   ;argument 2 decides function
-        #endif
-        
-        #ifdef LARGE_MEMORY ;If large memory (>64K) ELPM is needed to use RAMPZ        
-        ELPM                ;read LSB        
-        #else
-        LPM                 
-        #endif
-
-        MOV     R16,R0      ;read LSB           
-        INC     R30
-
-        #ifdef LARGE_MEMORY ;If large memory (>64K) ELPM is needed to use RAMPZ        
-        ELPM                ;read LSB        
-        #else
-        LPM                 
-        #endif
-
-        MOV     R17,R0      ;read MSB (ignored when reading lockbits)
-
-        RET
-
-write_lock_bits:
-        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
-
-        MOV     R0,R16   
-        LDI     R17,((1<<BLBSET)|(1<<SPMEN))
-
-        #ifdef _ATMEGA104
-        STS     SPMCSR,R17  ;argument 2 decides function
-        #else
-        OUT     SPMCR,R17   ;argument 2 decides function
-        #endif
-
-        _SPM                ;write lockbits
-
-        DW      0xFFFF      ;For future part compatibility, instruction alignment
-        NOP
-        
-        RCALL   WAIT_SPMEN  ;Wait for SPMEN flag cleared
-
-WAIT_SPMEN:
-        #ifdef _ATMEGA104
-        LDS     R19,SPMCSR
-        SBRC    R19,SPMEN
-        RJMP    WAIT_SPMEN  ;Wait for SPMEN flag cleared
-        #endif
-        
-        RET
-
-	END
\ No newline at end of file
diff -urN avr109-dist/cstartup.s90 avr109-gcc/cstartup.s90
--- avr109-dist/cstartup.s90	Thu Aug 16 11:42:32 2001
+++ avr109-gcc/cstartup.s90	Wed Dec 31 19:00:00 1969
@@ -1,180 +0,0 @@
-;----------------------------------------------------------------------------
-;		    CSTARTUP.S90
-;
-;	This module contains the AVR C and EC++ startup
-;	routine and must usually be tailored to suit
-;	customer's hardware.
-;
-;   File version:   $Revision: 1.5 $
-;
-;----------------------------------------------------------------------------
-#include	"macros.m90"
-
-;----------------------------------------------------------------------------
-; Set up the INTVEC segment with a reset vector		
-;----------------------------------------------------------------------------
-        NAME	?RESET
-;         NAME C_STARTUP   
-
-        EXTERN  ?C_STARTUP
-;        PUBLIC  __RESTART
-
-	COMMON	INTVEC:CODE:ROOT(1)	; Align at an even address
-
-;        EXTERN  ?C_STARTUP
-
-	ORG	$0
-;__RESTART:
-	XJMP	?C_STARTUP
-
-        ENDMOD
-
-;----------------------------------------------------------------------------
-; Forward declarations of segments used in initialization
-;----------------------------------------------------------------------------
-	RSEG	CSTACK(0)
-	RSEG	RSTACK(0)
-
-;----------------------------------------------------------------------------
-; Perform C initialization
-;----------------------------------------------------------------------------
-	MODULE	?C_STARTUP
-
-	EXTERN	__low_level_init
-	EXTERN	__segment_init
-#ifdef _ECLIB
-	EXTERN	__call_ctors
-#endif /* _ECLIB */
-	EXTERN	main
-	EXTERN	exit
-	EXTERN	_exit
-
-;----------------------------------------------------------------------------
-; If the return address stack is located in external SRAM, make sure that
-; you have uncommented the correct code in __low_level_init!!!
-;----------------------------------------------------------------------------
-	RSEG	CODE:CODE:NOROOT(1)
-	PUBLIC	?C_STARTUP
-	PUBLIC	__RESTART
-
-__RESTART:
-?C_STARTUP:
-	REQUIRE	?SETUP_STACK
-
-	RSEG	CODE:CODE:NOROOT(1)
-	PUBLIC	__RSTACK_in_external_ram
-
-__RSTACK_in_external_ram:
-        LDI     R16,0xC0
-        OUT     0x35,R16	;Enable the external SRAM with a wait state
-
-;----------------------------------------------------------------------------
-; Set up the CSTACK and RSTACK pointers.
-;----------------------------------------------------------------------------
-	RSEG	CODE:CODE:NOROOT(1)
-?SETUP_STACK:
-	;; Return address stack (RSTACK)
-	LDI	R16,LOW(SFE(RSTACK))
-        SUBI    R16,0x03
-	OUT	0x3D,R16
-#if A90_POINTER_REG_SIZE > 1
-	LDI	R16,HIGH(SFE(RSTACK))
-        SBCI    R16,0x00
-	OUT	0x3E,R16
-#endif
-
-	;; Data stack (CSTACK)
-	LDI	Y0,LOW(SFE(CSTACK))
-#if A90_POINTER_REG_SIZE > 1
-	LDI	Y1,HIGH(SFE(CSTACK))
-#if A90_POINTER_REG_SIZE > 2
-        LDI	Z0,HWRD(SFE(CSTACK))
-        OUT     RAMPY,Z0
-#endif
-#endif
-
-	REQUIRE	?call_low_level_init
-
-;----------------------------------------------------------------------------
-; Clear R15 so that it can be used as zero register by the code generator.
-; The compiler will emit a "REQUIRE ?zero_reg_initialization" statement if
-; this optimization has been enabled.
-;----------------------------------------------------------------------------
-	RSEG	CODE:CODE:NOROOT(1)
-	PUBLIC	?zero_reg_initialization
-
-?zero_reg_initialization:
-	CLR	R15
-
-;----------------------------------------------------------------------------
-; Call __low_level_init to do low level initializatons. Modify the supplied
-; __low_level_init module to add your own initialization code or to
-; remove segment initialization (by returning 0).
-;----------------------------------------------------------------------------
-	RSEG	CODE:CODE:NOROOT(1)
-	PUBLIC	?call_low_level_init
-
-?call_low_level_init:
-	XCALL	__low_level_init
-
-	REQUIRE	?cstartup_call_main
-
-;----------------------------------------------------------------------------
-; Call __segment_init to initialize segments.
-;----------------------------------------------------------------------------
-	RSEG	CODE:CODE:NOROOT(1)
-	PUBLIC	?need_segment_init
-
-?need_segment_init:
-	TST	P0
-	BREQ	?skip_segment_init
-	XCALL	__segment_init
-?skip_segment_init:
-
-;----------------------------------------------------------------------------
-;	Call the constructors of all global objects. This code will only
-;	be used if any EC++ modules defines global objects that need to
-;	have its constructor called before main.
-;----------------------------------------------------------------------------
-#ifdef _ECLIB
-	RSEG	DIFUNCT(0)
-#endif /* _ECLIB */
-	RSEG	CODE:CODE:NOROOT(1)
-
-	PUBLIC	?call_ctors
-
-?call_ctors:
-#ifdef _ECLIB
-	LDI	P0,LOW(SFB(DIFUNCT))
-	LDI	P1,SFB(DIFUNCT) >> 8
-
-	LDI	P2,LOW(SFE(DIFUNCT))
-	LDI	P3,SFE(DIFUNCT) >> 8
-
-	XCALL	__call_ctors
-#endif /* _ECLIB */
-
-;----------------------------------------------------------------------------
-;	Call main
-;----------------------------------------------------------------------------
-	RSEG	CODE:CODE:NOROOT(1)
-
-	PUBLIC	?cstartup_call_main
-
-?cstartup_call_main:
-#if MEMORY_MODEL != LARGE_MEMORY_MODEL
-#if A90_PROC_OPTION > 1
-	LDI	R16,0
-	OUT	RAMPZ,R16
-#if A90_POINTER_REG_SIZE > 2
-	OUT	RAMPY,R16
-	OUT	RAMPX,R16
-#endif /* A90_POINTER_REG_SIZE > 2 */
-#endif /* A90_PROC_OPTION > 1 */
-#endif /* MEMORY_MODEL != LARGE_MEMORY_MODEL */
-
-	XCALL	main
-	XCALL	exit
-	XJMP	_exit
-
-	END
diff -urN avr109-dist/defines.h avr109-gcc/defines.h
--- avr109-dist/defines.h	Thu Aug 16 12:54:42 2001
+++ avr109-gcc/defines.h	Mon Mar  4 03:15:58 2002
@@ -1,7 +1,7 @@
 /* Select Device (Select one, comment out the others) */
-#define _ATMEGA32
+//#define _ATMEGA32
 //#define _ATMEGA161 
-//#define _ATMEGA163 
+#define _ATMEGA163 
 //#define _ATMEGA128 
 
 /* Select Boot Size (select one, comment out the others).
@@ -17,8 +17,8 @@
 // Define pin for enter selfprogramming mode
 #define PROGPORT PORTD
 #define PROGPIN PIND
-#define PROGCTRL (1<<PD4)
-#define PROGMODE !(PROGPIN & PROGCTRL)  // TRUE if PROGCTRL on PROGPIN is low
+#define PROGCTRL PD4
+#define PROGMODE !(inp(PROGPIN) & (1<<PROGCTRL))  // TRUE if PROGCTRL on PROGPIN is low
 
 #ifdef _ATMEGA32 
   #include "iom32.h"
diff -urN avr109-dist/lnk3s.xcl avr109-gcc/lnk3s.xcl
--- avr109-dist/lnk3s.xcl	Wed Aug 15 14:32:24 2001
+++ avr109-gcc/lnk3s.xcl	Wed Dec 31 19:00:00 1969
@@ -1,52 +0,0 @@
-/*                      - lnk3s.xcl -
- *
- *   XLINK command file for the ICCAVR C-compiler
- *
- *
- *   File version:   $Name:  $
- */
-
-/*
- * Modify the lines below to alter the size of the RSTACK, CSTACK and HEAP
- * segments. These need to be fine tuned to suit your specific application.
- * The '_..X_' prefix is used by C-SPY as an indication that the label should
- * not be displayed in the dissassembly window.
- */
--D_..X_CSTACK_SIZE=100  /* 256 bytes for auto variables and saved registers. */
--D_..X_RSTACK_SIZE=40   /* 64 bytes for return addresses, equivalent to 32 */
-                        /* levels of calls, including interrupts. */
--D_..X_HEAP_SIZE=80     /* 128 bytes of heap. */
-
-/* Define CPU */
--ca90
-
-/*
- * The following segments are located in the internal memory.
- * Do not change these lines.
- */
-
-/* Code memory */
-
-// Program address space (internal Flash memory) ATmega161,ATmega163 w. 512 word boot block
-//-Z(CODE)INTVEC,FAR_F,SWITCH,CODE=3C00-3FFF
-
-// Program address space (internal Flash memory) ATmega323 w. 512 word boot block
--Z(CODE)INTVEC,FAR_F,SWITCH,CODE=7C00-7FFF
-
-// Program address space (internal Flash memory) ATmega128 w. 512 word boot block
-//-Z(CODE)INTVEC,FAR_F,SWITCH,CODE=1FC00-1FFFF
-
-
-/* Internal data memory */
--Z(DATA)TINY_I,TINY_Z,TINY_N=100-10FF
--Z(DATA)NEAR_I,NEAR_Z=100-45F
--Z(DATA)RSTACK+_..X_RSTACK_SIZE=100-45F
--Z(DATA)CSTACK+_..X_CSTACK_SIZE=100-45F
--Z(DATA)HEAP+_..X_HEAP_SIZE=100-45F
-
-/* Internal eeprom memory */
--Z(XDATA)EEPROM_I,EEPROM_N,EEPROM_AN=0-1FF
-
-/* Suppress one warning which is not relevant for this processor */
--w29
-
diff -urN avr109-dist/main.c avr109-gcc/main.c
--- avr109-dist/main.c	Thu Aug 16 12:49:42 2001
+++ avr109-gcc/main.c	Mon Mar  4 03:18:37 2002
@@ -35,11 +35,12 @@
 *                 the used part's boot address and size. Note that memory size
 *                 is specified in bytes in the linker file.
 ****************************************************************************/
+#include <io.h>
 #include "defines.h"
 #include "serial.h"
 #include "assembly.h"
 
-__C_task void main(void)
+int main(void)
 {
     void (*funcptr)( void ) = 0x0000;       // Set up function pointer   
    
@@ -47,30 +48,29 @@
     unsigned char val, ldata;
 
 #ifdef _ATMEGA32
-    UBRRL = 1;                            // 115200bps @ 3.69 MHz
-//    UBRRL = 11;                         // 19200bps @ 3.69 MHz
-    UCSRB = (1<<RXEN) | (1<<TXEN);      // Enable recieve and transmit UART1
+    outp (1, UBRRL);                            // 115200bps @ 3.69 MHz
+//    outp(11, UBRRL);                         // 19200bps @ 3.69 MHz
+    outp ((1<<RXEN) | (1<<TXEN), UCSRB);      // Enable receive and transmit UART1
 #endif
 
 #ifdef _ATMEGA161
-    UBRR0 = 11;                          // 19200bps @ 3.69 MHz
-    UCSR0B = (1<<RXEN0) | (1<<TXEN0);      // Enable recieve and transmit UART1
+    outp (11, UBRR0);                          // 19200bps @ 3.69 MHz
+    outp ((1<<RXEN0) | (1<<TXEN0), UCSR0B);      // Enable receive and transmit UART1
 #endif
 
 #ifdef _ATMEGA163
-    UBRRLO = 11;                          // 19200bps @ 3.69 MHz
-    UCSRB = (1<<RXEN) | (1<<TXEN);        // Enable recieve and transmit
+    outp (11, UBRR);                            // 19200bps @ 3.69 MHz
+    outp ((1<<RXEN) | (1<<TXEN), UCSRB);        // Enable receive and transmit
 #endif
 
 #ifdef _ATMEGA128
-    UBRR1L = 1;                            // 115200bps @ 3.69 MHz
-//    UBRR1L = 11;                          // 19200bps @ 3.69 MHz
-    UCSR1B = (1<<RXEN) | (1<<TXEN);        // Enable recieve and transmit
+    outp (1, UBRR1L);                            // 115200bps @ 3.69 MHz
+//    outp (11, UBRR1L);                          // 19200bps @ 3.69 MHz
+    outp ((1<<RXEN) | (1<<TXEN), UCSR1B);        // Enable receive and transmit
 #endif
 
-    PROGPORT |= PROGCTRL;               //enable pull-up on PROGCTRL line on PROGPORT
-    if(PROGMODE)                       //If PROGPIN is pulled low: programmingmode. 
-    {  
+    sbi (PROGPORT, PROGCTRL);    //enable pull-up on PROGCTRL line on PROGPORT
+    if (PROGMODE) {      //If PROGPIN is pulled low: programming mode.
       for(;;)                           
       {
         val=recchar();
@@ -183,25 +183,24 @@
         }
         else if (val == 'D')
         {
-          EEARL = address;
-          EEARH = (address >> 8);
+          outp (address, EEARL);
+          outp (address >> 8, EEARH);
           address++;
-          EEDR = recchar();
-          EECR |= (1<<EEMWE);
-          EECR |= (1<<EEWE);
-          while (EECR & (1<<EEWE))
+	  outp (recchar(), EEDR);
+	  sbi (EECR, EEMWE);
+          while (inp (EECR) & (1<<EEWE))
             ;
           sendchar('\r');
         }
 
         else if (val == 'd')
         {
-          EEARL = address;
-          EEARH = (address >> 8);
+          outp (address, EEARL);
+          outp (address >> 8, EEARH);
           address++;
-          EECR |= (1<<EERE);
-          sendchar(EEDR);
-        }       
+	  outp ((1<<EERE) | inp (EECR), EECR);
+          sendchar(inp (EEDR));
+        }
         else if(val=='F')                   // read fuse bits
         {
           #ifdef LARGE_MEMORY
@@ -272,4 +271,5 @@
     {
       funcptr();        					// Jump to Reset vector 0x0000 in Application Section
     }
+  return 0; 
 }
diff -urN avr109-dist/main.lcf avr109-gcc/main.lcf
--- avr109-dist/main.lcf	Wed Dec 31 19:00:00 1969
+++ avr109-gcc/main.lcf	Mon Mar  4 03:15:59 2002
@@ -0,0 +1,7 @@
+/* linker control file for main.c */
+
+MEMORY
+{
+  /* put everything at word address 0x1e00 (linker is in units of bytes) */
+  text (rx) : ORIGIN = 0x3c00, LENGTH = 0x400
+}
diff -urN avr109-dist/serial.c avr109-gcc/serial.c
--- avr109-dist/serial.c	Mon Jul  9 15:17:30 2001
+++ avr109-gcc/serial.c	Mon Mar  4 03:15:59 2002
@@ -1,31 +1,38 @@
+#include <io.h>
 #include "defines.h"
 
 void sendchar(char c)
 {
 #ifdef _ATMEGA32
-   UDR=c;
-   while (!(UCSRA & (1<<TXC)));                     //wait until byte sendt
-   UCSRA |= (1<<TXC);                               //delete TXCflag
+   outp (c, UDR);
+   while (!(inp(UCSRA) & (1<<TXC)));                     //wait until byte sendt
+   sbi (UCSRA, TXC);                               //delete TXCflag
 #endif
 #ifdef _ATMEGA161
-   UDR0=c;
-   while (!(UCSR0A & (1<<TXC0)));                   //wait until byte sendt
-   UCSR0A |= (1<<TXC0);                             //delete TXCflag
+   outp (c, UDR0);
+   while (!(inp(UCSR0A) & (1<<TXC0)));                   //wait until byte sendt
+   sbi (UCSR0A, TXC0);                             //delete TXCflag
 #endif
 #ifdef _ATMEGA163
-   UDR=c;
-   while (!(UCSRA & (1<<TXC)));                     //wait until byte sendt
-   UCSRA |= (1<<TXC);                               //delete TXCflag
+   outp (c, UDR);
+   while (!(inp(UCSRA) & (1<<TXC)));                     //wait until byte sendt
+   sbi (UCSRA, TXC);                              //delete TXCflag
 #endif
 #ifdef _ATMEGA104
-   UDR1=c;
-   while (!(UCSR1A & (1<<TXC)));                    //wait until byte sendt
-   UCSR1A |= (1<<TXC);                              //delete TXCflag
+   outp (c, UDR1);
+   while (!(inp(UCSR1A) & (1<<TXC)));                    //wait until byte sendt
+   sbi (UCSR1A, TXC);                               //delete TXCflag
 #endif
 
 }
 
-char recchar(void)
+// recchar must be unsigned char, or the compiler will sign extend its
+// result, and the address code in main.c is trashed.
+//        address=recchar();
+//        address=(address<<8)|recchar();
+// With signed char, the second recchar() is sign extended so that 0x80
+// turns into 0xff80, and the high order address bits are lost.
+unsigned char recchar(void)
 {
 #ifdef _ATMEGA32
    while(!(UCSRA & (1<<RXC)));                      // Wait for data to come
@@ -36,8 +43,8 @@
    return UDR0;
 #endif
 #ifdef _ATMEGA163
-   while(!(UCSRA & (1<<RXC)));                      // Wait for data to come
-   return UDR;
+   while(!(inp(UCSRA) & (1<<RXC)));                      // Wait for data to come
+   return inp(UDR);
 #endif
 #ifdef _ATMEGA104
    while(!(UCSR1A & (1<<RXC)));                     // Wait for data to come
diff -urN avr109-dist/serial.h avr109-gcc/serial.h
--- avr109-dist/serial.h	Thu Jun 17 16:18:34 1999
+++ avr109-gcc/serial.h	Mon Mar  4 03:15:59 2002
@@ -1,2 +1,2 @@
 void sendchar( char );
-char recchar( void );
+unsigned char recchar( void );