#ifndef __KERNEL_H__
#define __KERNEL_H__

#include "commdefs.h"
#include "rtos_defs.h"
#include "process.h"

extern "C" void OS_Start(StackItem* sp);
extern "C" void SysTick_Handler(void);
extern "C" StackItem* OS_ContextSwitchHook(StackItem* sp);

class TKernel
{
	friend class TISRW;

	public:
		TKernel()
			: _curProcPriority(pr0)
			, _readyProcessMap( (1 << (PROCESS_COUNT + 1)) - 1)  // set all processes ready
			, _ISR_NestCount(0)
		{
		}

		void	Run();
		dword	GetTickCount();
		void	RegisterProcess(BaseProcess* const p, uint8_t priority) { _processTable[priority] = p; }
		void	Scheduler() { if (_ISR_NestCount) return; else  Sched(); }

		void ReadyProcess(const uint8_t pr) { ProcessMap prioTag = getPrioTag(pr); setPrioTag( _readyProcessMap, prioTag); }
		void BlockProcess(const uint8_t pr) { ProcessMap prioTag = getPrioTag(pr); clrPrioTag( _readyProcessMap, prioTag); }

		BaseProcess* Running(void) { return _processTable[_curProcPriority]; }

		void Tick();
		StackItem* ContextSwitchHook(StackItem* sp);

	private:

		uint8_t getHighPriority(ProcessMap pm)
		{
			dword clzero;
			asm ("clz\t%0, %1": "=r" (clzero): "r" (pm));
			return (31 - clzero);
		}

		ProcessMap getPrioTag(const uint8_t pr) 					{ return static_cast<ProcessMap> (1 << pr); }
		void setPrioTag(ProcessMap& pm, const ProcessMap prioTag)	{ pm |=  prioTag; }
		void clrPrioTag(ProcessMap& pm, const ProcessMap prioTag)	{ pm &= ~prioTag; }

		void Sched();
		void SchedISR();
		bool IsContextSwitchDone() const volatile 					{ return (_curProcPriority == _schedProcPriority); }


	private:
		uint8_t				_curProcPriority;
		ProcessMap 			_readyProcessMap;
		BaseProcess* 		_processTable[PROCESS_COUNT+1];
		volatile uint8_t 	_ISR_NestCount;
		uint8_t 			_schedProcPriority;
		volatile dword 		_sysTickCount;
};

#endif // __KERNEL_H__
