/*
*	ARM state codes, with intertrupts disabled.
*/

#define	ARM_STATE_USR	0xd0	// User
#define	ARM_STATE_FIQ	0xd1	// Fast interrupt service
#define	ARM_STATE_IRQ	0xd2	// Interrupt service
#define	ARM_STATE_SUP	0xd3	// Supervisor
#define	ARM_STATE_ABT	0xd7	// Abort (data or fetch)
#define	ARM_STATE_UND	0xdb	// Undefined insn
#define	ARM_STATE_SYS	0xdf	// System, same as user but with privileges

/*
*	The vector table must reside at address 0. We put it into its own
*	segment, so that we can guarantee that it will get to there regardless
*	of linking order. The vector table is actually instructions, not just
*	vectors. The exception is the sixth vector, which is not used on the
*	ARM7TDMI. The LPC2xxx chips put a checksum of the vector table there,
*	which is used by the chip's bootloader to check if it has valid code
*	in the FLASH or not. Regardless of the microcontroller type it is safe
*	to set that location to 0.
*/

		.section	.vector
		b		reset			// Reset
		b		fatal			// Undefined insn
		b		fatal			// SWI
		b		fatal			// Prefetch abort
		b		fatal			// Data abort
		.word	0				// Reserved (LPC code integrity word is here)
		b		inter			// IRQ
		b		fatal			// FIQ

/*
*	Reset code. This goes into the code segment. Customarily .text is used
*	as the segment name.
*
*	After reset the processor is in ARM mode, IRQ state with both IRQ and FIQ
*	disabled. Apart from the CPSR (status register) and the PC nothing is
*	initialised, not even the stack pointer.
*
*	We first clear the .bss segment and copy the initialiser data from the
*	FLASH to the data segment. We have five symbols that are defined by the
*	linker for us:
*	_init_beg	Start of the initialiser in the FLASH
*	_data_beg	Start of the data segment
*	_data_end	End of the data segment
*	_bss_beg	Start of the uninitilised data segment
*	_bss_end	End of the uninitilised data segment
*
*	These symbols are all aligned to word boundaries.
*
*	After that we set up the stacks, select the correct processor state
*	and start the execution of the actual code.
*
*	Since it is a simple example, we will only have one stack. The code will
*	be execute in system state. No interrupts are supported; any exception,
*	including the normal interrupt is fatal.
*
*	When we start the system (i.e. we jump to the main() function) we do not
*	know whether it is an ARM or a THUMB function. Thus, we use the bx insn
*	that will switch to the correct mode.
*/

	.text
reset:

	// Initialise .data and clear .bss

	adr		r0,addr_table			// Get the address of the table
	ldmia	r0,{r1-r5}				// Load all addresses into registers
	mov		r0,#0					// We will store 0 in the .bss
	b		1f						// Start with the compare
0:	str		r0,[r4],#4				// Store a 0, increment the pointer
1:	cmp		r4,r5					// Did we reach the end?
	bne		0b						// If not, keep going
	b		1f						// Init data segment, start with compare
0:	ldr		r0,[r1],#4				// Get a word from the FLASH, ptr++
	str		r0,[r2],#4				// Store it in .data, ptr++
1:	cmp		r2,r3					// Are we at the end of .data?
	bne		0b						// If not, keep going

	// Set up the stack and processor state. We are in IRQ state.

	ldr		r0,stack_ptr			// Get the satck
	mov		sp, r0					// Load the stackpointer
	msr		cpsr_c,#ARM_STATE_FIQ	// Put the processor to FIQ state
	mov		sp, r0					// Load the stackpointer
	msr		cpsr_c,#ARM_STATE_ABT	// Put the processor to abort state
	mov		sp, r0					// Load the stackpointer
	msr		cpsr_c,#ARM_STATE_UND	// Put the processor to undef.insn. state
	mov		sp, r0					// Load the stackpointer
	msr		cpsr_c,#ARM_STATE_SUP	// Put the processor to supervisor state
	mov		sp, r0					// Load the stackpointer
	msr		cpsr_c,#ARM_STATE_SYS	// Put the processor to system state
	mov		sp, r0					// Load the stackpointer

	// All stakpointers are set up. We're in system state.
	// Start the system.

	ldr		r0,entry_point			// Get the address of the entry point
	bx		r0						// and start it

/*
*	This is the table of the linker-defined symbols
*/

addr_table:
	.word	_init_beg				// Start of the initialiser in the FLASH
	.word	_data_beg				// Start of the data segment
	.word	_data_end				// End of the data segment
	.word	_bss_beg				// Start of the uninitilised data segment
	.word	_bss_end				// End of the uninitilised data segment

/*
*	Address of the stack and address of the system entry point
*/

stack_ptr:
	.word	stack					// The stack

entry_point:
	.word	main					// Address of main()

/*
*	Fatal error exception
*
*	We do nothing, just sit in a loop. Hopefully the system started the]
*	watchdog, so we will be reset. Just to be on the safe side, we
*	disable all interrupts and swith to system mode.
*/

fatal:
	msr		cpsr_c,#ARM_STATE_SYS	// System state, IRQ, FIQ disabled
0:	b		0b						// Neverending loop.

/*
*	This is the system stack. We put it into the .bss.
*	On the ARM the stack pointer points to the TOS, not one before.
*	We allocate 1K of stack.
*/

	.bss
	.align	2						// Alignment to 2^2=4 boundary
	.space	1024					// 1K stack
stack:								// Bottom of the stack

	.end

