/*
*	Prototypes for the functions we use
*/

		void system_boot( void ) __attribute__ ((noreturn));
static	void system_init( void ) __attribute__ ((noreturn));
static	void interrupt( void );
static	void idle( void );
static	void boot_hardware( void );

/*
*	Definition of various parameters
*/

#define EVENTQ_LEN	30		// Event queue is 30 events long
#define	EVENTQ_WM	20		// Event watermark is 20 events
#define	MAIN_STACK	256		// Init process stack is 1KB (256 words)
#define KERN_STACK	256		// The kernel's stack is 1KB

/*
*	This will be the process descriptor for the main process. We make it
*	public, so others can send events to this process
*/

BX_PROC main_proc;

/*
*	Local data
*/

static int events[ EVENTQ_LEN * 3 ];	// The kernel's event queue
static int main_stack[ INIT_STACK ];	// The stack for the main process
static int kern_stack[ KERN_STACK ];	// The stack for the kernel itself

/*
*	These are defined by the linker, they are the start and end of the
*	various segments. We assume that the initialised data segment's
*	initailisers are placed in the FLASH just after the code.
*/

extern char __end_code[];				// End of the code segment
extern char __beg_data[];				// Start of the data segment
extern char __end_data[];				// End of the data segment
extern char __beg_bss[];				// Start of the bss segment
extern char __end_bss[];				// End of the bss segment

/*
*	This is the init structure. We initialise it using gcc's named field
*	extension, this makes it safer. We define it const, so gcc will put
*	it into FLASH.
*/

static const BX_INIT init = {

	.evtq_size	= EVENTQ_LEN,				// Length of the event queue
	.evtq_wmrk	= EVENTQ_WM,				// Interrupt watermark
	.evtq_buff	= events,					// Memory for the event queue
	.uirq_func	= interrupt,				// Interrupt handler function
	.idle_func	= idle,						// Idle state handler
	.init_desc	= &main_proc,				// Init process descriptor
	.init_func	= main,						// Init process function
	.init_stack = main_stack + MAIN_STACK	// Note: BOTTOM of stack!
	.kern_stack = kern_stack + KERN_STACK	// Note: BOTTOM of stack!
};

/*
*	This is the function that is called after reset.
*	It is entered in IRQ mode, with IRQ and FIQ both disabled.
*	The only thing that has been set up is a few stacks, nothing else.
*	This function will never return, it will pass control to the first
*	thread instead.
*/

void sys_boot( void )
{
	// Load the initialised data (copy it from FLASH to RAM)

	memcpy( __beg_data, __end_code, __end_data - __beg_data );

	// Clear the BSS Note that the interrupt stack is NOT in the
	// BSS segment, thus this is safe to do.

	memset( __beg_bss, 0, __end_bss - __beg_bss );

	// Boot the processor hardware, such as clock PLL, power management etc.

	boot_hardware();	// This function is omitted from the example

	// Now we're ready to start the system. BX_Init() will never return.

	BX_Init( &init );
}

/*
*	This is the idle function.
*	It must *NOT* call any kernel functions. It can enable interrupts, but
*	it should not, unless it is really necessary. It is called with IRQ
*	disabled and supposed to sit here until an interrupt becomes pending.
*	If your microcontroller does not have a way to stop the core while
*	waiting for interrupts, you can leave this function empty. We now
*	assume that the microcontroller has a HW register that will stop
*	the core immediately and the core will resume operation if an interrupt
*	becomes pending (even though the core does not accept interrupts at the
*	moment).
*/

static void idle( void )
{
	// Send the CPU core to sleep. The instruction will stop
	// the core and it will wake up when an interrupt becomes
	// active.

	SOME_MCU_REG = VALUE_THAT_TURNS_THE_CORE_OFF;
}

/*
*	This is the handler for IRQs
*	Note that the function does not and must not have an interrupt attribute,
*	it is a normal C function. It can even be a THUMB function, if you enable
*	interworking.
*/

static void interrupt( void )
{
void (*isr)( void );

	// Get the address of the ISR function from the interrupt controller

	isr = SOME_MCU_REGISTER;

	// Call the ISR

	(*isr)();

	// Do whatever we have to to make the interrupt controller happy

	SOME_MCU_REGISTER = VALUE_TO_ACKNOWLEDGE_INTERRUPTS;
}

/*
*	This function is the entry point of the first thread.
*	It will be started with IRQ and FIQ disabled and with the highest priority.
*	It runs in system state (like all threads) using its own stack, main_stack
*	and its process descriptor is main_proc.
*/

static void main( void )
{
	// Start all subprocesses, init resources etc. Note that all
	// interrupts are disabled, nothing can interfere with us.
	// The threads you start will just sit there, ready to run
	// but this function will retain control.

	start_all_subsystems();

	// Now drop our priority to the level we should be on, let's
	// say it is 10. Note that even if we've started processes
	// with higher priority, we'll still be running because we
	// are in protected mode.

	BX_ProcNice( 10 );

	// Drop our protection level to normal. That will enable all
	// interrupts and, if there is any process with a priority
	// greater than ours, will cause a context switch.
	// From now on we're just a normal process.

	BX_ProcProtDrop( BX_PROT_NORM );

	// As any normal process, we should not return, just sit in a
	// loop (probably processing events).

	for (;;) {

		signal = BX_SignalWait( .. );
		...
	}
}

