/*
  Copyright (c) 2008-2012  John Lee (j.y.lee@yeah.net)
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution.

  * Neither the name of the copyright holders nor the names of
    contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef __LIGHTWEIGHT_OBJECT_ORENTED_KERNEL_H
#error "Include <look.h> instead of this file."
#elif !defined(__GNUG__)
#error This header file must only be compiled by GNU C++ compiler.
#elif (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || (__GNUC__ < 4)
#error GCC 4.3 or greater is required.
#elif !defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_7M__)
#error This header file must only be compiled for ARMv6-M and ARMv7-M architecture.
#else

#ifndef __LOOK_INTERFACE
#define __LOOK_INTERFACE

#pragma interface

#include <cstdint>

#define __LOOK_VERSION__	0x20111018UL

#define LOOK_HWINIT()		LOOK_HWINIT_PRIORITY(5)
#define LOOK_HWINIT_PRIORITY(PRIORITY)	__LOOK_HWINIT(__COUNTER__, PRIORITY)

#if !defined(__DOXYGEN__)
#ifdef __INLINE
#undef __INLINE
#endif	// __INLINE
#define __INLINE			__attribute__((always_inline)) inline

#ifdef __WEAK
#undef __WEAK
#endif	// __WEAK
#define __WEAK				__attribute__((noinline, weak))

#ifndef __CONCAT
#define __CONCAT(a, b)		__CONCAT_I(a, b)
#define __CONCAT_I(a, b)	a ## b
#endif	// __CONCAT

#define __LOOK_HWINIT(CNT, PRIORITY)									\
	__attribute__((constructor(101 + PRIORITY))) static void __CONCAT(look_hwinit_, CNT)()

#define LOOK_SVC(_N, _R, _F, ...)			\
	({										\
		register auto f asm ("ip") = reinterpret_cast<void (*)()>(_F);	\
		register _R result asm ("r0");		\
		__asm__ __volatile__(				\
			"svc %[n]"	"\n\t"				\
			: "=r" (result)					\
			: [n] "i" (_N), "r" (f), ##__VA_ARGS__	\
			: "memory"						\
		);									\
		result;								\
	})

#ifdef __ARM_ARCH_6M__
#define look	look_armv6m
#else
#define look	look_armv7m
#endif	// __ARM_ARCH_6M__
#endif	// !__DOXYGEN__

namespace look {
	class signal_sink_t {
	public:
		__INLINE signal_sink_t();
		virtual void on_signal(void* addr, uintptr_t signal);
	};

	class interrupt_t : public signal_sink_t {
	public:
		__INLINE interrupt_t();
		__INLINE interrupt_t* attach(uint_fast8_t irq);

	private:
		virtual bool isr(int vector) = 0;
		virtual void dsr(int vector, uintptr_t count) = 0;
	};

	class vector_t {
		friend class interrupt_t;
		friend class systick_t;

	public:
		__INLINE static void enable(uint_fast8_t irq);
		__INLINE static void disable(uint_fast8_t irq);
		__INLINE static void set_priority(uint_fast8_t irq, uint_fast8_t priority);

	private:

#ifndef __DOXYGEN__
		__INLINE interrupt_t* attach(interrupt_t* intr);
#endif	// __DOXYGEN__

		static void stack();
		static void reset();
		static void libc_reset();
		static void dsr();
		static void nmi();
		static void hard_fault();
		static void vsr();

#ifdef __ARM_ARCH_7M__
		static void mem_manage();
		static void bus_fault();
		static void usage_fault();
		static void debug_monitor();
#endif	// __ARM_ARCH_7M__

#ifndef __DOXYGEN__
		union {
			struct {
				interrupt_t* interrupt;
				uint16_t count;
				uint8_t next;
			};
			uint64_t data;
		};
#endif	// __DOXYGEN__

		__attribute__((aligned(4))) static vector_t table[];
		__attribute__((section(".vector"), used)) static void (*const vectors[])();
	};

	class timer_t {
	public:
		__INLINE timer_t(signal_sink_t& sink);
		__INLINE uintptr_t start(uintptr_t interval);
		__INLINE uintptr_t kill();
		__INLINE uintptr_t do_start(uintptr_t interval);
		__INLINE uintptr_t do_kill();

	private:
		uintptr_t count;
		signal_sink_t* sink;
		timer_t* next;
		timer_t* prev;
	};

	class systick_t : public interrupt_t {
	public:
		__INLINE systick_t(uintptr_t reload, uint_fast8_t priority = 0);
		__INLINE uintptr_t get_jiffies() const;
		__INLINE uintptr_t set_timer(timer_t& timer, uintptr_t interval);
		__INLINE uintptr_t kill_timer(timer_t& timer);
		uintptr_t do_set_timer(timer_t& timer, uintptr_t interval);

	protected:
		bool isr(int vector);
		void dsr(int vector, uintptr_t count);

	private:
		volatile uintptr_t jiffies;
		uintptr_t internal_data[8];
	};

	namespace base {
		class task_t;
	}

	class sync_t {
	public:
		__INLINE sync_t();

	protected:
		__INLINE base::task_t* wakeup(uintptr_t data, base::task_t* task = 0);
		__INLINE base::task_t* do_wakeup(uintptr_t data, base::task_t* task = 0);

	protected:
		uintptr_t internal_data;
	};

	class sem_t : public sync_t {
	public:
		__INLINE sem_t(uintptr_t cnt = 0);
		__INLINE uintptr_t get_count() const;

#ifdef __ARM_ARCH_6M__
		__INLINE bool trywait();
#else	// __ARM_ARCH_6M__
		bool trywait();
#endif	// __ARM_ARCH_6M__

		__INLINE bool wait(uintptr_t timeout = 0);
		__INLINE void post();

		bool do_trywait();
		bool do_post();

#ifndef __DOXYGEN__
	private:
		uintptr_t count;
#endif	// __DOXYGEN__

	};

	class mbox_base_t : public sync_t {
	protected:
		__INLINE mbox_base_t(uintptr_t size);
		__INLINE uintptr_t get_entries() const;

#ifndef __DOXYGEN__
		__INLINE bool tryget(uintptr_t& msg);
		__INLINE bool get(uintptr_t& msg, uintptr_t timeout = 0);
		__INLINE bool tryput(uintptr_t msg, bool front);
		__INLINE bool put(uintptr_t msg, bool front, uintptr_t timeout = 0);
		bool do_tryget(uintptr_t& msg);
		bool do_tryput(uintptr_t msg, bool front);

	protected:
		uint8_t size;
		uint8_t in;
		uint8_t out;
		uint8_t entries;
#endif	// __DOXYGEN__

	};

	template<typename QUEUE, typename T, uint8_t SIZE>
	class queue_t : public QUEUE {
	public:
		__INLINE uintptr_t get_size() const;
		__INLINE bool peek(T& msg) const;

		__INLINE bool tryget(T& msg);
		__INLINE bool get(T& msg, uintptr_t timeout = 0);
		__INLINE bool tryput(T msg);
		__INLINE bool tryput_front(T msg);
		__INLINE bool put(T msg, uintptr_t timeout = 0);
		__INLINE bool put_front(T msg, uintptr_t timeout = 0);

		__INLINE bool do_tryget(T& msg);
		__INLINE bool do_tryput(T msg);
		__INLINE bool do_tryput_front(T msg);

	protected:
		__INLINE queue_t();

#ifndef __DOXYGEN__
	private:
		T buffer[SIZE];
#endif	// __DOXYGEN__

	};

	template<typename T, uint8_t SIZE>
	class mbox_t : public queue_t<mbox_base_t, T, SIZE> {
		static_assert(sizeof(T) == sizeof(uintptr_t), "the type argument for <T> must be same size as uintptr_t");
		static_assert(SIZE > 0 && SIZE < 256, "<SIZE> must be greater than 0 and less than 256");

	public:
		__INLINE mbox_t();
	};

	class idle_task_t : public signal_sink_t {
	public:
		enum {
			MIN_CONTEXT_SIZE = 16
		};

	protected:
		__INLINE idle_task_t();

	protected:
		void init(uintptr_t& context, void* routine);

	private:
		uintptr_t* context;
		uintptr_t info;
	};

	extern idle_task_t idle_task;

	namespace base {
		class flag_t : public sync_t {
		public:
			enum mode_t {
				ANY_KEEP,
				ANY_CONSUME,
				ALL_KEEP,
				ALL_CONSUME,
				LSB_KEEP,
				LSB_CONSUME
			};

		public:
			__INLINE uintptr_t peek() const;

#ifdef __ARM_ARCH_6M__
			__INLINE uintptr_t poll(uintptr_t pattern, mode_t mode);
			__INLINE void mask_bits(uintptr_t pattern);
#else	// __ARM_ARCH_6M__
			uintptr_t poll(uintptr_t pattern, mode_t mode);
			void mask_bits(uintptr_t pattern);
#endif	// __ARM_ARCH_6M__

			__INLINE uintptr_t wait(uintptr_t pattern, mode_t mode, uintptr_t timeout = 0);

			uintptr_t do_poll(uintptr_t pattern, mode_t mode);
			void do_mask_bits(uintptr_t pattern);

		protected:
			__INLINE flag_t(uintptr_t flags);

#ifndef __DOXYGEN__
		protected:
			uintptr_t flags;
#endif	// __DOXYGEN__

		};

		class task_t : public idle_task_t {
		public:
			__INLINE bool wakeup();
			bool do_wakeup();

		protected:
			__INLINE task_t();

		protected:
			void on_signal(void* addr, uintptr_t signal);
		};

		class sched_t : public signal_sink_t {
			friend class look::vector_t;
			friend class look::sync_t;

		public:
			__INLINE void lock();
			__INLINE void unlock();
			__INLINE void unlock_reschedule();
			__INLINE void reschedule();

			void do_reschedule();
			void do_unlock_reschedule();

			__INLINE task_t& get_current_task();

		protected:
			__INLINE sched_t();

#ifndef __DOXYGEN__
			task_t* do_wakeup(sync_t& sync, task_t* task, uintptr_t result);
#endif	// __DOXYGEN__

		protected:
			virtual task_t* dispatch() = 0;
			virtual task_t* ready(sync_t& sync, task_t* task = 0) = 0;
			virtual void block(sync_t& sync) = 0;

		private:
			static void svcall();
			static void pendsv();

		protected:
			task_t* cur_task;
			uint16_t lock_count;
			uint16_t internal_data;
		};
	}

	namespace link {
		class flag_t : public base::flag_t {
		public:
			__INLINE flag_t(uintptr_t flags = 0);
			__INLINE void set_bits(uintptr_t pattern);
			void do_set_bits(uintptr_t pattern);
		};

		class task_t : public base::task_t {
		protected:
			__INLINE task_t();

		private:
			task_t* next;
			task_t* prev;
		};
	}

	class rest_site_t : public sync_t {
	public:
		__INLINE void rest(uintptr_t timeout = 0);

	private:
		void do_rest();
	};

	extern rest_site_t rest_site;
	extern uintptr_t version;

#ifdef __ARM_ARCH_7M__
	__INLINE bool set_privilege(bool state);
	bool do_set_privilege(bool state);
#endif	// __ARM_ARCH_7M__

	__INLINE void delay(uintptr_t timeout = 0);
	__INLINE uintptr_t get_version();
}
#else	// __LOOK_INTERFACE
#ifndef __LOOK_INLINE
#define __LOOK_INLINE
__INLINE look::signal_sink_t::signal_sink_t()
{
}

__INLINE look::interrupt_t::interrupt_t()
{
}

__INLINE look::interrupt_t* look::interrupt_t::attach(uint_fast8_t irq)
{
	return vector_t::table[irq - -1/*SysTick_IRQn*/].attach(this);
}

__INLINE void look::vector_t::enable(uint_fast8_t irq)
{
	reinterpret_cast<volatile uint32_t*>(0xe000e100)[irq >> 5] = 1 << (irq & 31);
}

__INLINE void look::vector_t::disable(uint_fast8_t irq)
{
	reinterpret_cast<volatile uint32_t*>(0xe000e180)[irq >> 5] = 1 << (irq & 31);
}

#ifndef __DOXYGEN__
__INLINE look::interrupt_t* look::vector_t::attach(interrupt_t* intr)
{
	interrupt_t* old = interrupt;
	interrupt = intr;
	return old;
}
#endif	// __DOXYGEN__

__INLINE void look::vector_t::set_priority(uint_fast8_t irq, uint_fast8_t priority)
{
	reinterpret_cast<volatile uint8_t*>(0xe000e400)[irq] = priority;
}

__INLINE look::timer_t::timer_t(signal_sink_t& sink)
{
	this->sink = &sink;
	next = 0;
}

__INLINE uintptr_t look::timer_t::start(uintptr_t interval)
{
	return systick.set_timer(*this, interval);
}

__INLINE uintptr_t look::timer_t::kill()
{
	return start(0);
}

__INLINE uintptr_t look::timer_t::do_start(uintptr_t interval)
{
	return systick.do_set_timer(*this, interval);
}

__INLINE uintptr_t look::timer_t::do_kill()
{
	return do_start(0);
}

__INLINE look::systick_t::systick_t(uintptr_t reload, uint_fast8_t priority)
{
	vector_t::table[0].attach(this);
	*reinterpret_cast<volatile uint8_t*>(0xe000ed23) = priority;
	volatile uintptr_t* scs = reinterpret_cast<volatile uintptr_t*>(0xe000e000);
	__asm__ __volatile__("" : "+r" (scs));
	scs[6] = reload;
	scs[5] = reload;
	scs[4] = 7;
}

__INLINE uintptr_t look::systick_t::get_jiffies() const
{
	return jiffies;
}

__INLINE uintptr_t look::systick_t::set_timer(timer_t& timer, uintptr_t interval)
{
	register auto _this asm ("a1") = this;
	register auto _timer asm ("a2") = &timer;
	register auto _interval asm ("a3") = interval;
	return LOOK_SVC(0, uintptr_t, &systick_t::do_set_timer, "0" (_this), "r" (_timer), "r" (_interval));
}

__INLINE uintptr_t look::systick_t::kill_timer(timer_t& timer)
{
	return set_timer(timer, 0);
}

__INLINE look::sync_t::sync_t()
{
	internal_data = 0;
}

__INLINE look::base::task_t* look::sync_t::wakeup(uintptr_t data, base::task_t* task)
{
	register auto _scheduler asm ("a1") = &scheduler;
	register auto _this asm ("a2") = this;
	register auto _task asm ("a3") = task;
	register auto _data asm ("a4") = data;
	return LOOK_SVC(0, base::task_t*, &sched_t::do_wakeup, "0" (_scheduler), "r" (_this), "r" (_task), "r" (_data));
}

__INLINE look::base::task_t* look::sync_t::do_wakeup(uintptr_t data, base::task_t* task)
{
	return scheduler.do_wakeup(*this, task, data);
}

__INLINE look::sem_t::sem_t(uintptr_t cnt)
{
	count = cnt;
}

__INLINE uintptr_t look::sem_t::get_count() const
{
	return count;
}

#ifdef __ARM_ARCH_6M__
__INLINE bool look::sem_t::trywait()
{
	register auto _this asm ("a1") = this;
	return LOOK_SVC(0, bool, &sem_t::do_trywait, "0" (_this));
}
#endif	// __ARM_ARCH_6M__

__INLINE bool look::sem_t::wait(uintptr_t timeout)
{
	register auto _this asm ("a1") = this;
	register auto _timeout asm ("a2") = timeout;
	return LOOK_SVC(1, bool, &sem_t::do_trywait, "0" (_this), "r" (_timeout));
}

__INLINE void look::sem_t::post()
{
	register auto _this asm ("a1") = this;
	LOOK_SVC(0, uintptr_t, &sem_t::do_post, "0" (_this));
}

__INLINE look::mbox_base_t::mbox_base_t(uintptr_t size)
{
	this->size = size;
	in = out = entries = 0;
}

__INLINE uintptr_t look::mbox_base_t::get_entries() const
{
	return entries;
}

#ifndef __DOXYGEN__
__INLINE bool look::mbox_base_t::tryget(uintptr_t& msg)
{
	register auto _this asm ("a1") = this;
	register auto _msg asm ("a2") = &msg;
	return LOOK_SVC(0, bool, &mbox_base_t::do_tryget, "0" (_this), "r" (_msg));
}

__INLINE bool look::mbox_base_t::get(uintptr_t& msg, uintptr_t timeout)
{
	register auto _this asm ("a1") = this;
	register auto _msg asm ("a2") = &msg;
	register auto _timeout asm ("a3") = timeout;
	return LOOK_SVC(2, bool, &mbox_base_t::do_tryget, "0" (_this), "r" (_msg), "r" (_timeout));
}

__INLINE bool look::mbox_base_t::tryput(uintptr_t msg, bool front)
{
	register auto _this asm ("a1") = this;
	register auto _msg asm ("a2") = msg;
	register auto _front asm ("a3") = front;
	return LOOK_SVC(0, bool, &mbox_base_t::do_tryput, "0" (_this), "r" (_msg), "r" (_front));
}

__INLINE bool look::mbox_base_t::put(uintptr_t msg, bool front, uintptr_t timeout)
{
	register auto _this asm ("a1") = this;
	register auto _msg asm ("a2") = msg;
	register auto _front asm ("a3") = front;
	register auto _timeout asm ("a4") = timeout;
	return LOOK_SVC(3, bool, &mbox_base_t::do_tryput, "0" (_this), "r" (_msg), "r" (_front), "r" (_timeout));
}
#endif	// __DOXYGEN__

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE look::queue_t<QUEUE, T, SIZE>::queue_t()
: QUEUE(SIZE)
{
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE uintptr_t look::queue_t<QUEUE, T, SIZE>::get_size() const
{
	return SIZE;
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::peek(T& msg) const
{
	if (QUEUE::entries) {
		msg = buffer[QUEUE::out];
		return true;
	}
	return false;
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::tryget(T& msg)
{
	return QUEUE::tryget(reinterpret_cast<uintptr_t&>(msg));
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::get(T& msg, uintptr_t timeout)
{
	return QUEUE::get(reinterpret_cast<uintptr_t&>(msg), timeout);
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::tryput(T msg)
{
	return QUEUE::tryput(uintptr_t(msg), false);
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::tryput_front(T msg)
{
	return QUEUE::tryput(uintptr_t(msg), true);
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::put(T msg, uintptr_t timeout)
{
	return QUEUE::put(uintptr_t(msg), false, timeout);
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::put_front(T msg, uintptr_t timeout)
{
	return QUEUE::put(uintptr_t(msg), true, timeout);
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::do_tryget(T& msg)
{
	return QUEUE::do_tryget(reinterpret_cast<uintptr_t&>(msg));
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::do_tryput(T msg)
{
	return QUEUE::do_tryput(uintptr_t(msg), false);
}

template<typename QUEUE, typename T, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, T, SIZE>::do_tryput_front(T msg)
{
	return QUEUE::do_tryput(uintptr_t(msg), true);
}

template<typename T, uint8_t SIZE>
__INLINE look::mbox_t<T, SIZE>::mbox_t()
: queue_t<mbox_base_t, T, SIZE>()
{
}

__INLINE look::base::flag_t::flag_t(uintptr_t flags)
{
	this->flags = flags;
}

__INLINE uintptr_t look::base::flag_t::peek() const
{
	return flags;
}

#ifdef __ARM_ARCH_6M__
__INLINE uintptr_t look::base::flag_t::poll(uintptr_t pattern, mode_t mode)
{
	register auto _this asm ("a1") = this;
	register auto _pattern asm ("a2") = pattern;
	register auto _mode asm ("a3") = mode;
	return LOOK_SVC(0, uintptr_t, &flag_t::do_poll, "0" (_this), "r" (_pattern), "r" (_mode));
}

__INLINE void look::base::flag_t::mask_bits(uintptr_t pattern)
{
	register auto _this asm ("a1") = this;
	register auto _pattern asm ("a2") = pattern;
	LOOK_SVC(0, uintptr_t, &flag_t::do_mask_bits, "0" (_this), "r" (_pattern));
}
#endif	// __ARM_ARCH_6M__

__INLINE uintptr_t look::base::flag_t::wait(uintptr_t pattern, mode_t mode, uintptr_t timeout)
{
	register auto _this asm ("a1") = this;
	register auto _pattern asm ("a2") = pattern;
	register auto _mode asm ("a3") = mode;
	register auto _timeout asm ("a4") = timeout;
	return LOOK_SVC(3, uintptr_t, &flag_t::do_poll, "0" (_this), "r" (_pattern), "r" (_mode), "r" (_timeout));
}

__INLINE look::link::flag_t::flag_t(uintptr_t flags)
: base::flag_t(flags)
{
}

__INLINE void look::link::flag_t::set_bits(uintptr_t pattern)
{
	register auto _this asm ("a1") = this;
	register auto _pattern asm ("a2") = pattern;
	LOOK_SVC(0, uintptr_t, &flag_t::do_set_bits, "0" (_this), "r" (_pattern));
}

__INLINE look::idle_task_t::idle_task_t()
{
}

__INLINE look::base::task_t::task_t()
{
}

__INLINE bool look::base::task_t::wakeup()
{
	register auto _this asm ("a1") = this;
	return LOOK_SVC(0, bool, &task_t::do_wakeup, "0" (_this));
}

__INLINE look::base::sched_t::sched_t()
{
	lock_count = 1;
	internal_data = 1;
}

__INLINE void look::base::sched_t::lock()
{
	uintptr_t cnt = lock_count;
	cnt++;
	lock_count = cnt;
}

__INLINE void look::base::sched_t::unlock()
{
	uintptr_t count = lock_count - 1;
	if (count != 0)
		lock_count = count;
	else
		unlock_reschedule();
}

__INLINE void look::base::sched_t::reschedule()
{
	register auto _this asm ("a1") = this;
	LOOK_SVC(0, uintptr_t, &sched_t::do_reschedule, "0" (_this));
}

__INLINE void look::base::sched_t::unlock_reschedule()
{
	register auto _this asm ("a1") = this;
	LOOK_SVC(0, uintptr_t, &sched_t::do_unlock_reschedule, "0" (_this));
}

__INLINE look::base::task_t& look::base::sched_t::get_current_task()
{
	return *cur_task;
}

#ifndef __DOXYGEN__
__INLINE void look::rest_site_t::rest(uintptr_t timeout)
{
	register auto _this asm ("a1") = this;
	register auto _timeout asm ("a2") = timeout;
	LOOK_SVC(1, uintptr_t, &rest_site_t::do_rest, "0" (_this), "r" (_timeout));
}
#endif	// __DOXYGEN__

__INLINE void look::delay(uintptr_t timeout)
{
	rest_site.rest(timeout);
}

__INLINE look::link::task_t::task_t()
{
}

#ifdef __ARM_ARCH_7M__
__INLINE bool look::set_privilege(bool state)
{
	register bool _state asm ("a1") = state;
	return LOOK_SVC(0, bool, &do_set_privilege, "0" (_state));
}
#endif	// __ARM_ARCH_7M__

__INLINE uintptr_t look::get_version()
{
	return reinterpret_cast<uintptr_t>(&version);
}
#endif	// __LOOK_INLINE
#endif	// __LOOK_INTERFACE
#endif	// __LIGHTWEIGHT_OBJECT_ORENTED_KERNEL_H
