#ifndef __DOXYGEN
#include <avr/io.h>
#if E2END && __AVR_ARCH__ > 1
#include <avr/eeprom.h>
#include "asmdef.h"
#include "eedef.h"
ENTRY   eeprom_write_byte
    mov r18, r22
ENTRY   eeprom_write_r18
#if  __AVR_XMEGA__  
# ifndef CCP_IOREG_gc
#  define CCP_IOREG_gc  0xD8    
# endif
# ifndef NVM_CMD_READ_EEPROM_gc
#  define NVM_CMD_READ_EEPROM_gc        0x06
# endif
# ifndef NVM_CMD_LOAD_EEPROM_BUFFER_gc
#  define NVM_CMD_LOAD_EEPROM_BUFFER_gc     0x33
# endif
# ifndef NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc
#  define NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc    0x35
# endif
# ifndef  NVM_CMD_ERASE_EEPROM_BUFFER_gc
#  define NVM_CMD_ERASE_EEPROM_BUFFER_gc    0x36
# endif
#if    ! defined (NVM_EEMAPEN_bm)
  ; Saving X register because it might contain source address of block
    push XL
    push XH
#endif
  ; Prepare base address of NVM.
    ldi ZL, lo8(NVM_BASE)
    ldi ZH, hi8(NVM_BASE)
  ; Wait until NVM is not busy.
1:  ldd r19, Z + NVM_STATUS - NVM_BASE
    sbrc    r19, NVM_NVMBUSY_bp
    rjmp    1b
  ; It has to be noted that for some Xmega parts (Eg. Xmega E family) EEPROM
  ; is always memory mapped. So it is not possible to disable EEPROM mapping
  ; explicitly. 
  ; The presence of NVM_EEMAPEN_bm macro (from the part header file) can be
  ; checked to find out whether the device supports enabling/disabling of
  ; EEPROM mapping. Absence of NVM_EEMAPEN_bm could be interpreted safely as
  ; EEPROM always memory mapped and explicit memory mapping of EEPROM is not 
  ; required/invalid.
#if     defined (NVM_EEMAPEN_bm)
  ; Disable EEPROM mapping into data space.
    ldd r19, Z + NVM_CTRLB - NVM_BASE
    andi    r19, ~NVM_EEMAPEN_bm
    std Z + NVM_CTRLB - NVM_BASE, r19
  ; Check the clearance of EEPROM page buffer.
    ldd r19, Z + NVM_STATUS - NVM_BASE
    sbrs    r19, NVM_EELOAD_bp
    rjmp    3f          ; erase is not required
  ; Note that we have only four clock cycles to write to the CCP
  ; protected register NVM_CTRLA, after writing to CCP.  The 'ldi'
  ; instruction always takes one clock to execute and 'std' instruction takes
  ; two clock cycles.  We fall within the four cycles that the CCP leaves
  ; us to write the command execution start bit to the NVM_CTRLA
  ; register.  Note that r18 must be preserved until written to NVM_DATA0
  ; Issue EEPROM Buffer Erase:
    ldi r19, NVM_CMD_ERASE_EEPROM_BUFFER_gc
    std Z + NVM_CMD - NVM_BASE, r19
    ldi r19, CCP_IOREG_gc
    out CCP, r19
    ldi r19, NVM_CMDEX_bm
    std Z + NVM_CTRLA - NVM_BASE, r19
  ; Wait until NVM is not busy.
2:  ldd r19, Z + NVM_STATUS - NVM_BASE
    sbrc    r19, NVM_NVMBUSY_bp
    rjmp    2b
  ; Issue EEPROM Buffer Load command.
3:  ldi r19, NVM_CMD_LOAD_EEPROM_BUFFER_gc
    std Z + NVM_CMD - NVM_BASE, r19
#endif
    std Z + NVM_ADDR0 - NVM_BASE, addr_lo
    std Z + NVM_ADDR1 - NVM_BASE, addr_hi
    std Z + NVM_ADDR2 - NVM_BASE, __zero_reg__
#if     defined (NVM_EEMAPEN_bm)
    std Z + NVM_DATA0 - NVM_BASE, r18
#else
    movw    XL, addr_lo
    subi    XL, lo8(-MAPPED_EEPROM_START)
    sbci    XH, hi8(-MAPPED_EEPROM_START)
    st  X, r18
#endif
  ; Issue EEPROM Erase & Write command.
    ldi r18, NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc
    std Z + NVM_CMD - NVM_BASE, r18
    ldi r18, CCP_IOREG_gc
    ldi r19, NVM_CMDEX_bm
    out CCP, r18
    std Z + NVM_CTRLA - NVM_BASE, r19
  ; Increment address.
    adiw    addr_lo, 1
#if    ! defined (NVM_EEMAPEN_bm)
  ; Restoring X register
    pop XH
    pop XL
#endif    
    ret
#else       
1:  sbic    _SFR_IO_ADDR (EECR), EEWE
    rjmp    1b
# if     defined (EEPM0) && defined (EEPM1)
    ; Set programming mode: erase and write.
    out _SFR_IO_ADDR (EECR), __zero_reg__
# elif   defined (EEPM0) || defined (EEPM1)
#  error    
# endif
# ifdef  EEARH
#  if     E2END > 0xFF
    out _SFR_IO_ADDR (EEARH), addr_hi
#  else
    ; This is for chips like ATmega48: the EEAR8 bit must be cleaned.
    out _SFR_IO_ADDR (EEARH), __zero_reg__
#  endif
# endif
    out _SFR_IO_ADDR (EEARL), addr_lo
    out _SFR_IO_ADDR (EEDR), r18
    in  __tmp_reg__, _SFR_IO_ADDR (SREG)
    cli
    sbi _SFR_IO_ADDR (EECR), EEMWE
    sbi _SFR_IO_ADDR (EECR), EEWE
    out _SFR_IO_ADDR (SREG), __tmp_reg__
    adiw    addr_lo, 1
    ret
#endif      
ENDFUNC
#endif  
#endif