INTERFACE [arm && !kern_start_0xd]:

EXTENSION class Mem_layout
{
public:
  enum Virt_layout_umax : Address {
    User_max             = 0xc0000000,
  };
};


//---------------------------------------------------------------------------
INTERFACE [arm && kern_start_0xd]:

EXTENSION class Mem_layout
{
public:
  enum Virt_layout_umax : Address {
    User_max             = 0xd0000000,
  };
};


//---------------------------------------------------------------------------
INTERFACE [arm]:

#include "template_math.h"

EXTENSION class Mem_layout
{
public:
  enum Virt_layout : Address {
    Utcb_addr            = User_max - 0x10000,
    Service_page         = 0xeac00000,
    Tbuf_status_page     = Service_page + 0x5000,
    Tbuf_ustatus_page    = Tbuf_status_page,
    Tbuf_buffer_area	 = Service_page + 0x200000,
    Tbuf_ubuffer_area    = Tbuf_buffer_area,
    Jdb_tmp_map_area     = Service_page + 0x400000,
    __free_1_start       = 0xee000000,
    __free_1_end         = 0xef000000,
    Cache_flush_area     = 0xef000000,
    Cache_flush_area_end = 0xef100000,
    Registers_map_start  = 0xef100000,
    Registers_map_end    = 0xeff00000,
    Map_base             = 0xf0000000,
    Map_end              = 0xf5000000,
    Caps_start           = 0xf5000000,
    Caps_end             = 0xfd000000,
    Utcb_ptr_page        = 0xffffd000,
    // don't care about caches here, because arm uses a register on MP
    utcb_ptr_align       = Tl_math::Ld<sizeof(void*)>::Res,
    Kern_lib_base	 = 0xffffe000,
    Ivt_base             = 0xffff0000,
    Syscalls		 = 0xfffff000,

    Kernel_max           = 0x00000000,

    Devices0_map_base    = Registers_map_start + 0x00000000,
    Devices1_map_base    = Registers_map_start + 0x00100000,
    Devices2_map_base    = Registers_map_start + 0x00200000,
    Devices3_map_base    = Registers_map_start + 0x00300000,
    Devices4_map_base    = Registers_map_start + 0x00400000,
    Devices5_map_base    = Registers_map_start + 0x00500000,
    Devices6_map_base    = Registers_map_start + 0x00600000,
    Devices7_map_base    = Registers_map_start + 0x00700000,
    Devices8_map_base    = Registers_map_start + 0x00800000,
    Devices9_map_base    = Registers_map_start + 0x00900000,
  };
};

// -------------------------------------------------------------------------
IMPLEMENTATION [arm]:

//---------------------------------
// Workaround GCC BUG 33661
// Do not use register asm ("r") in a template function, it will be ignored
//---------------------------------
PUBLIC static inline
bool
Mem_layout::_read_special_safe(Mword const *address, Mword &v)
{
  register Mword a asm("r14") = (Mword)address;
  Mword ret;
  asm volatile ("msr cpsr_f, #0    \n" // clear flags
                "ldr %[a], [%[a]]  \n"
		"movne %[ret], #1      \n"
		"moveq %[ret], #0      \n"

                : [a] "=r" (a), [ret] "=r" (ret)
                : "0" (a)
                : "cc");
  v = a;
  return ret;
}

PUBLIC static inline
template< typename V >
bool
Mem_layout::read_special_safe(V const *address, V &v)
{
  Mword _v;
  bool ret = _read_special_safe(reinterpret_cast<Mword const*>(address), _v);
  v = V(_v);
  return ret;
}

//---------------------------------
// Workaround GCC BUG 33661
// Do not use register asm ("r") in a template function, it will be ignored
//---------------------------------
PUBLIC static inline
Mword
Mem_layout::_read_special_safe(Mword const *a)
{
  register Mword const *res __asm__ ("r14") = a;
  __asm__ __volatile__ ("ldr %0, [%0]\n" : "=r" (res) : "r" (res) : "cc" );
  return Mword(res);
}

PUBLIC static inline
template< typename T >
T
Mem_layout::read_special_safe(T const *a)
{
  return T(_read_special_safe((Mword const *)a));
#if 0
  Mword res;
  asm volatile ("msr cpsr_f, #0; ldr %0, [%1]; moveq %0, #0\n"
		: "=r" (res) : "r" (a) : "cc");
  return T(res);
#endif
}

PUBLIC static inline
bool
Mem_layout::is_special_mapped(void const *a)
{
  register Mword pagefault_if_0 asm("r14");
  asm volatile ("msr cpsr_f, #0 \n" // clear flags
                "ldr %0, [%0]   \n"
		"movne %0, #1   \n"
		"moveq %0, #0   \n"
		: "=r" (pagefault_if_0) : "0" (a) : "cc");
  return pagefault_if_0;
}
