////////////////////////////////////////////////////////////////////////////
//
//  File        :  arm_arch.lsl
//
//  Version     :  @(#)arm_arch.lsl     1.4  09/04/17
//
//  Description :  Generic LSL file for ARM architectures
//
//  Copyright 2008-2009 Altium BV
//
////////////////////////////////////////////////////////////////////////////

#ifndef __STACK
#  define __STACK                       32k
#endif
#ifndef __HEAP
#  define __HEAP                        32k
#endif
#ifndef __STACK_FIQ
#  define __STACK_FIQ                   8
#endif
#ifndef __STACK_IRQ
#  define __STACK_IRQ                   8
#endif
#ifndef __STACK_SVC
#  define __STACK_SVC                   8
#endif
#ifndef __STACK_ABT
#  define __STACK_ABT                   8
#endif
#ifndef __STACK_UND
#  define __STACK_UND                   8
#endif
#ifndef __PROCESSOR_MODE
#  define __PROCESSOR_MODE              0x1F            /* SYS mode */
#endif
#ifndef __IRQ_BIT
#  define __IRQ_BIT                     0x80            /* IRQ interrupts disabled */
#endif
#ifndef __FIQ_BIT
#  define __FIQ_BIT                     0x40            /* FIQ interrupts disabled */
#endif

#define __APPLICATION_MODE              (__PROCESSOR_MODE | __IRQ_BIT | __FIQ_BIT)

#ifndef __VECTOR_TABLE_ROM_ADDR
#  define __VECTOR_TABLE_ROM_ADDR       0x00000000
#endif

#ifndef __VECTOR_TABLE_RAM_ADDR
#  define __VECTOR_TABLE_RAM_ADDR       0x00000000
#endif

#if defined(__CPU_ARMV7M__) || defined(__CPU_ARMV6M__)
#  ifndef __NR_OF_VECTORS
#    define __NR_OF_VECTORS             16
#  endif
#  define __VECTOR_TABLE_SIZE           (__NR_OF_VECTORS * 4)
#else
#  ifdef __PIC_VECTORS
#    define __VECTOR_TABLE_SIZE         64
#  else
#    ifdef __FIQ_HANDLER_INLINE
#      define __VECTOR_TABLE_SIZE       28
#      define __NR_OF_VECTORS           7
#    else
#      define __VECTOR_TABLE_SIZE       32
#      define __NR_OF_VECTORS           8
#    endif
#  endif
#endif

#ifndef __VECTOR_TABLE_RAM_SPACE
#  undef __VECTOR_TABLE_RAM_COPY
#endif

#ifndef __XVWBUF
#  define __XVWBUF                      0               /* buffer used by CrossView Pro */
#endif

#define BOUNDS_GROUP_NAME       grp_bounds
#define BOUNDS_GROUP_SELECT     "bounds"

architecture ARM
{
        endianness
        {
                little;
                big;
        }

        space linear
        {
                id = 1;
                mau = 8;
                map (size = 4G, dest = bus:local_bus);

                copytable
                (
                        align = 4,
                        copy_unit = 1,
                        dest = linear
                );

                start_address
                (
                        // It is not strictly necessary to define a run_addr for _START
                        // because hardware starts execution at address 0x0 which should
                        // be the vector table with a jump to the relocatable _START, but
                        // an absolute address can prevent the branch to be out-of-range.
                        // Or _START may be the entry point at reset and the reset handler
                        // copies the vector table to address 0x0 after some ROM/RAM memory
                        // re-mapping. In that case _START should be at a fixed address
                        // in ROM, specifically the alias of address 0x0 before memory
                        // re-mapping.
#ifdef __START
                        run_addr = __START,
#endif
                        symbol = "_START"
                );

                stack "stack"
                (
#ifdef __STACK_FIXED
                        fixed,
#endif
                        align = 4,
                        min_size = __STACK,
                        grows = high_to_low
                );

                heap "heap"
                (
#ifdef __HEAP_FIXED
                        fixed,
#endif
                        align = 4,
                        min_size=__HEAP
                );

#if !defined(__CPU_ARMV7M__) && !defined(__CPU_ARMV6M__)
                stack "stack_fiq"
                (
                        fixed,
                        align = 4,
                        min_size = __STACK_FIQ,
                        grows = high_to_low
                );
                stack "stack_irq"
                (
                        fixed,
                        align = 4,
                        min_size = __STACK_IRQ,
                        grows = high_to_low
                );
                stack "stack_svc"
                (
                        fixed,
                        align = 4,
                        min_size = __STACK_SVC,
                        grows = high_to_low
                );
                stack "stack_abt"
                (
                        fixed,
                        align = 4,
                        min_size = __STACK_ABT,
                        grows = high_to_low
                );
                stack "stack_und"
                (
                        fixed,
                        align = 4,
                        min_size = __STACK_UND,
                        grows = high_to_low
                );
#endif

#if !defined(__NO_AUTO_VECTORS) && !defined(__NO_DEFAULT_AUTO_VECTORS)
# if defined(__CPU_ARMV7M__) || defined(__CPU_ARMV6M__)
                // vector table with handler addresses
                vector_table "vector_table" ( vector_size = 4, size = __NR_OF_VECTORS, run_addr = __VECTOR_TABLE_ROM_ADDR,
                                              template = ".text.handler_address",
                                              template_symbol = "_lc_vector_handler",
                                              vector_prefix = "_vector_",
                                              fill = loop,
                                              no_inline
                                            )
                {
                        vector ( id = 0, fill = "_START" ); // FIXME: "_lc_ub_stack" does not work
                        vector ( id = 1, fill = "_START" );
                }
#  else
#    ifdef __PIC_VECTORS
                // vector table with ldrpc instructions from handler table
                vector_table "vector_table" ( vector_size = 4, size = 8, run_addr = __VECTOR_TABLE_ROM_ADDR,
                                              template = ".text.vector_ldrpc",
                                              template_symbol = "_lc_vector_ldrpc",
                                              vector_prefix = "_vector_ldrpc_",
                                              fill = loop
                                            )
                {
                }
                // subsequent vector table (data pool) with addresses of handlers
                vector_table "handler_table" ( vector_size = 4, size = 8, run_addr = __VECTOR_TABLE_ROM_ADDR + 32,
                                               template = ".text.handler_address",
                                               template_symbol = "_lc_vector_handler",
                                               vector_prefix = "_vector_",
                                               fill = loop[-32],
                                               no_inline
                                             )
                {
                        vector ( id = 0, fill = "_START" );
                }
#    else
                // vector table with branch instructions to handlers
                vector_table "vector_table" ( vector_size = 4, size = __NR_OF_VECTORS, run_addr = __VECTOR_TABLE_ROM_ADDR,
                                              template = ".text.vector_branch",
                                              template_symbol = "_lc_vector_handler",
                                              vector_prefix = "_vector_",
                                              fill = loop
                                            )
                {
                        vector ( id = 0, fill = "_START" );
                }
#    endif
#  endif
#endif
                section_layout
                {
#if defined(__NO_AUTO_VECTORS)
                        "_lc_ub_vector_table" = __VECTOR_TABLE_ROM_ADDR;
                        "_lc_ue_vector_table" = __VECTOR_TABLE_ROM_ADDR + __VECTOR_TABLE_SIZE;
#endif
#ifdef __VECTOR_TABLE_RAM_SPACE
                        // reserve space to copy vector table from ROM to RAM
                        group ( ordered, run_addr = __VECTOR_TABLE_RAM_ADDR )
                                reserved "vector_table_space" ( size = __VECTOR_TABLE_SIZE, attributes = rwx );
#endif
#ifdef __VECTOR_TABLE_RAM_COPY
                        // provide copy address symbols for copy routine
                        "_lc_ub_vector_table_copy" := "_lc_ub_vector_table_space";
                        "_lc_ue_vector_table_copy" := "_lc_ue_vector_table_space";
#else
                        // prevent copy: copy address equals orig address
                        "_lc_ub_vector_table_copy" := "_lc_ub_vector_table";
                        "_lc_ue_vector_table_copy" := "_lc_ue_vector_table";
#endif
                        // define buffer for string input via Crossview Pro debugger
                        group ( align = 4 ) reserved "xvwbuffer"  (size=__XVWBUF, attributes=rw );

                        // define labels for bounds begin and end as used in C library
#ifndef BOUNDS_GROUP_REDEFINED
                        group BOUNDS_GROUP_NAME (ordered, contiguous)
                        {
                                select BOUNDS_GROUP_SELECT;
                        }
#endif
                        "_lc_ub_bounds" := addressof(group:BOUNDS_GROUP_NAME);
                        "_lc_ue_bounds" := addressof(group:BOUNDS_GROUP_NAME) + sizeof(group:BOUNDS_GROUP_NAME);

#ifdef __HEAPADDR
                        group ( ordered, run_addr=__HEAPADDR )
                        {
                                select "heap";
                        }
#endif
#ifdef __STACKADDR
                        group ( ordered, run_addr=__STACKADDR )
                        {
                                select "stack";
                        }
#endif
#if !defined(__CPU_ARMV7M__) && !defined(__CPU_ARMV6M__)
                        // symbol to set mode bits and interrupt disable bits
                        // in cstart module before calling the application (main)
                        "_APPLICATION_MODE_" = __APPLICATION_MODE;
#endif
                }
        }

        bus local_bus
        {
                mau = 8;
                width = 32;
        }
}
