#define NUM_PROC	5		// The number of threads in the system
#define	NUM_PORT	2		// We have two threads that use message ports
#define	NUM_MESG	20		// We buffer up to 20 messages
#define	INIT_STK	128		// The init process will have 512 bytes of stack
#define	INIT_PID	0		// PID for the init thread


static BZ_PROC	procs[ NUM_PROC ];	// Memory reserved for threads (60 bytes)
static BZ_PORT	ports[ NUM_PORT ];	// Memory reserved for ports (8 bytes)
static BZ_MESG	mesgs[ NUM_MESG ];	// Memory reserved for messages (160 bytes)
static int		stack[ INIT_STK ];	// Stack for the first thread

/*
*	Local prototypes
*/

static void	Interrupt( void );
static void Idle( void );
static void	Init( void ) __attribute__((noreturn));

void SystemEntry( void ) __attribute__((noreturn));

/*
*	The configuration structure for the kernel
*/

static const BZ_INIT kernel_config = {

	.idle		= Idle,					// Idle function
	.irqs		= Interrupt,			// Interrupt handler function
	.init		= Init,					// Entry point of the first thread
	.init_stk	= stack + INIT_STK,		// Stack for the first thread
	.init_pid	= INIT_PID,				// Process ID for the first thread
	.proc_tab	= procs,				// Process table
	.proc_num	= NUM_PROC,				// Size of the process table
	.port_tab	= ports,				// Message ports
	.port_num	= NUM_PORT,				// Number of ports
	.mesg_tab	= mesgs,				// Message buffer pool
	.mesg_num	= NUM_MESG,				// Size of the pool
	.schedule	= 1						// We want priority scheduling
};

/*
*	This is where reset ends up after setting up the the
*	interrupt state and interrupt stack. At entry we're in
*	interrupt state and interrupts are disabled. We're using
*	the interrupt stack. This function never returns.
*/


void SystemEntry( void )
{
	// Clear the .bss and initialise .data

	...

	// Set up basic hardware, such as CPU clock, power, debug port, etc.

	...

	// Start the kernel. This call will not return, execution will continue
	// with entering Init() in system state, interrupts disabled.

	BZ_Init( &kernel_config );
}

/*
*	This is the idle function.
*	It is entered with interrupts disabled. It can either return without
*	doing anything or it can stop the CPU until an interrupt becomes pending,
*	in which case it will return immediately.
*	If you use an LPC2xxx processor, you can stop the CPU using a register
*	in the system control block. The processor will resume execution when
*	an interrupt becomes pending, even if the CPU itself is in disabled
*	interrupt state.
*/

static void	Idle( void )
{
	REGISTER_IN_SCB = STOP_THE_CPU_CLOCK;
}

/*
*	This is the interrupt handler entry point.
*	It is a normal C function, you MUST NOT declare it with and interrupt
*	attribute. The actual IRQ slot in the vector table should jump to the
*	BZ_IrqEntry function (provided by the kernel) and that will, after
*	the necessary prologue, call this function.
*	This function, in turn, has to call the actual interrupt handler for
*	whatever interrupt is pending. On the LPC2xxx chips the vectored
*	interrupt controller has a register that contains the function pointer
*	for the next highest priority interrupt; writing 0 to that register
*	acknowledges that interrupt and loads the register with the next pending
*	interrupt's (if any) service routine address. It also has a register
*	indicating whether there are any pending interrupts at all.
*/

static void	Interrupt( void )
{
	while ( VIC_INDICATES_PENDING_IRQ ) {

		(*VIC_REGISTER_CONTAINIG_THE_ISR_POINTER)();
		VIC_REGISTER_CONTAINIG_THE_ISR_POINTER = 0;
	}
}

/*
*	This is the first thread to run in the system.
*	It enters with interrupts disabled.
*/

static void Init( void )
{
	// Boot the hardware - we can't enable interrupts before
	// the hardware is ready.

	InitSomeHardware();
	...
	InitSomeOtherHardware();

	// Spawn all threads. They will not start to run,
	// merely registered as runnables.

	BZ_ProcSpawn( some_process ... );
	...
	BZ_ProcSpawn( last_process ... );

	// The system is ready, enable the interrupts and enter the
	// event loop - we're just a thread, like any other. This
	// also means thate we MUST NOT return.

	BZ_IrqDisable( 0 );

	for ( ;; ) {

		events = BZ_EventWait( event_list );

		if ( events & SOME_EVENT ) {

			...
		}

		...
	}
}

