<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX グループ・SCI I/O 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2013, 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/vect.h"

/// F_PCLKB はボーレートパラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCLKB
#  error "sci_io.hpp requires F_PCLKB to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SCI I/O 制御クラス
		@param[in]	SCI	SCI 定義クラス
		@param[in]	RECV_BUFF	受信バッファクラス
		@param[in]	SEND_BUFF	送信バッファクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SCI, class RECV_BUFF, class SEND_BUFF>
	class sci_io {

		static RECV_BUFF recv_;
		static SEND_BUFF send_;
		static volatile bool send_stall_;

		uint8_t	level_;
		bool	crlf_;

		// ※必要なら、実装する
		void sleep_() { asm("nop"); }

		static INTERRUPT_FUNC void recv_task_()
		{
			bool err = false;
			if(SCI::SSR.ORER()) {	///< 受信オーバランエラー状態確認
				SCI::SSR.ORER = 0;	///< 受信オーバランエラークリア
				err = true;
			}
			///< フレーミングエラー/パリティエラー状態確認
			if(SCI::SSR() & (SCI::SSR.FER.b() | SCI::SSR.PER.b())) {
				// エラーフラグの消去
				SCI::SSR.FER = 0;
				SCI::SSR.PER = 0;
				err = true;
			}
			volatile uint8_t data = SCI::RDR();
			if(!err) {
				recv_.put(data);
			}
		}

		static INTERRUPT_FUNC void send_task_()
		{
#if SIG_RX64M
			if(send_.length() > 0) {
				SCI::TDR = send_.get();
			}
			if(send_.length() == 0) {
				SCI::SCR.TIE = 0;
				send_stall_ = true;
			}
#else
			SCI::TDR = send_.get();
			if(send_.length() == 0) {
				SCI::SCR.TEIE = 0;
			}
#endif
		}

		void set_vector_(ICU::VECTOR rx_vec, ICU::VECTOR tx_vec) {
			if(level_) {
				set_interrupt_task(recv_task_, static_cast<uint32_t>(rx_vec));
				set_interrupt_task(send_task_, static_cast<uint32_t>(tx_vec));
			} else {
				set_interrupt_task(nullptr, static_cast<uint32_t>(rx_vec));
				set_interrupt_task(nullptr, static_cast<uint32_t>(tx_vec));
			}
		}

		void set_intr_() {
#if SIG_RX64M
			set_vector_(SCI::get_rx_vec(), SCI::get_tx_vec());
#else
			set_vector_(SCI::get_rx_vec(), SCI::get_te_vec());
#endif
			icu_mgr::set_level(SCI::get_peripheral(), level_);
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		sci_io() : level_(0), crlf_(true) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  ボーレートを設定して、SCI を有効にする @n
					※RX63T では、ポーリングはサポート外
			@param[in]	baud	ボーレート
			@param[in]	level	割り込みレベル（０の場合ポーリング）
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start(uint32_t baud, uint8_t level = 0) {
			send_stall_ = true;
#if SIG_RX63T
			if(level == 0) return false;
#endif
			crlf_ = true;
			level_ = level;

			SCI::SCR = 0x00;			// TE, RE disable.

			port_map::turn(SCI::get_peripheral());

			uint32_t brr = F_PCLKB / baud / 16;
			uint8_t cks = 0;
			while(brr > 512) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3) return false;
			bool abcs = true;
			if(brr > 256) { brr /= 2; abcs = false; }

			power_cfg::turn(SCI::get_peripheral());

			set_intr_();

			// 8 bits, 1 stop bit, no-parrity
			SCI::SMR = cks;
			SCI::SEMR.ABCS = abcs;
			if(brr) --brr;
			SCI::BRR = static_cast<uint8_t>(brr);

			if(level) {
				SCI::SCR = SCI::SCR.RIE.b() | SCI::SCR.TE.b() | SCI::SCR.RE.b();
			} else {
				SCI::SCR = SCI::SCR.TE.b() | SCI::SCR.RE.b();
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  通信速度を設定して、SPI を有効にする
			@param[in]	master	マスターモードの場合「true」
			@param[in]	bps	ビットレート
			@param[in]	level	割り込みレベル（０の場合ポーリング）
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start_spi(bool master, uint32_t bps, uint8_t level = 0)
		{
			send_stall_ = true;
			level_ = level;

			SCI::SCR = 0x00;			// TE, RE disable.

			uint32_t brr = F_PCLKB / bps / 2;
			if(brr & 1) { brr >>= 1; ++brr; }
			else { brr >>= 1; }
			uint8_t cks = 0;
			while(brr > 256) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3 || brr > 256) return false;

			power_cfg::turn(SCI::get_peripheral());

			set_intr_();

			// LSB(0), MSB(1) first
			SCI::SCMR.SDIR = 1;

			SCI::SIMR1.IICM = 0;
			SCI::SMR = cks | SCI::SMR.CM.b();
			SCI::SPMR.SSE = 0;		///< SS 端子制御しない「０」

			if(master) {
				SCI::SPMR.MSS = 0;
			} else {
				SCI::SPMR.MSS = 1;
			}

			// クロックタイミング種別選択
			SCI::SPMR.CKPOL = 0;
			SCI::SPMR.CKPH  = 0;

			if(brr) --brr;
			SCI::BRR = static_cast<uint8_t>(brr);

			uint8_t scr = 0;
			if(master) {
				scr = SCI::SCR.CKE.b(0b01);
			} else {
				scr = SCI::SCR.CKE.b(0b10);
			}

			if(level_) {
				SCI::SCR = SCI::SCR.RIE.b() | SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
			} else {
				SCI::SCR = SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	CRLF 自動送出
			@param[in]	f	「false」なら無効
		 */
		//-----------------------------------------------------------------//
		void auto_crlf(bool f = true) { crlf_ = f; }

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 出力バッファのサイズを返す
			@return　バッファのサイズ
		 */
		//-----------------------------------------------------------------//
		uint32_t send_length() const {
			if(level_) {
				return send_.length();
			} else {
				return 0;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字出力
			@param[in]	ch	文字コード
		 */
		//-----------------------------------------------------------------//
		void putch(char ch) {
			if(crlf_ && ch == '\n') {
				putch('\r');
			}

			if(level_) {
				volatile bool b = SCI::SSR.ORER();
				if(b) {
					SCI::SSR.ORER = 0;
				}
				/// 送信バッファの容量が７／８の場合は、空になるまで待つ。
				if(send_.length() >= (send_.size() * 7 / 8)) {
					while(send_.length() != 0) sleep_();
				}
				send_.put(ch);
#if SIG_RX64M
				SCI::SCR.TIE = 0;
				if(send_stall_) {
					while(SCI::SSR.TEND() == 0) sleep_();
					SCI::TDR = send_.get();
					if(send_.length() > 0) {
						send_stall_ = false;
					}
				}
				SCI::SCR.TIE = !send_stall_;
#else
				if(SCI::SCR.TEIE() == 0) {
					SCI::SCR.TEIE = 1;
				}
#endif
			} else {
				while(SCI::SSR.TEND() == 0) sleep_();
				SCI::TDR = ch;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 入力文字数を取得
			@return	入力文字数
		 */
		//-----------------------------------------------------------------//
		uint32_t recv_length() {
			if(level_) {
				return recv_.length();
			} else {
				if(SCI::SSR.ORER()) {	///< 受信オーバランエラー状態確認
					SCI::SSR.ORER = 0;	///< 受信オーバランエラークリア
				}
#if defined(SIG_RX64M) || defined(SIG_RX24T)
				auto n = SCI::SSR.RDRF();
#else
				uint32_t n = 0;
#endif
				return n;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字入力
			@return 文字コード
		 */
		//-----------------------------------------------------------------//
		char getch() {
			if(level_) {
				while(recv_.length() == 0) sleep_();
				return recv_.get();
			} else {
				char ch;
				while(recv_length() == 0) sleep_();
				ch = SCI::RDR();	///< 受信データ読み出し
				return ch;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	uart文字列出力
			@param[in]	s	出力ストリング
		 */
		//-----------------------------------------------------------------//
		void puts(const char* s) {
			char ch;
			while((ch = *s++) != 0) {
				putch(ch);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送受信
			@param[in]	ch	送信データ
			@return	受信データ
		*/
		//-----------------------------------------------------------------//
		inline uint8_t xchg(uint8_t ch = 0xff)
		{
			if(level_) {
				return 0;
			} else {
				SCI::TDR = ch;
				while(recv_length() == 0) sleep_();
				return SCI::RDR();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル送信
			@param[in]	src	送信ソース
			@param[in]	cnt	送信サイズ
		*/
		//-----------------------------------------------------------------//
		void send(const void* src, uint16_t size)
		{
			const uint8_t* p = static_cast<const uint8_t*>(src);
			auto end = p + size;
			while(p < end) {
				xchg(*p);
				++p;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル受信
			@param[out]	dst	受信先
			@param[in]	cnt	受信サイズ
		*/
		//-----------------------------------------------------------------//
		void recv(void* dst, uint16_t size)
		{
			uint8_t* p = static_cast<uint8_t*>(dst);
			auto end = p + size;
			while(p < end) {
				*p = xchg();
				++p;
			}
		}
	};

	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		RECV_BUFF sci_io<SCI, RECV_BUFF, SEND_BUFF>::recv_;
	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		SEND_BUFF sci_io<SCI, RECV_BUFF, SEND_BUFF>::send_;
	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		volatile bool sci_io<SCI, RECV_BUFF, SEND_BUFF>::send_stall_;
}
<commit_msg>update test interval for SPI<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX グループ・SCI I/O 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2013, 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/vect.h"

/// F_PCLKB はボーレートパラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCLKB
#  error "sci_io.hpp requires F_PCLKB to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SCI I/O 制御クラス
		@param[in]	SCI	SCI 定義クラス
		@param[in]	RECV_BUFF	受信バッファクラス
		@param[in]	SEND_BUFF	送信バッファクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SCI, class RECV_BUFF, class SEND_BUFF>
	class sci_io {

		static RECV_BUFF recv_;
		static SEND_BUFF send_;
		static volatile bool send_stall_;

		uint8_t	level_;
		bool	crlf_;

		// ※必要なら、実装する
		void sleep_() { asm("nop"); }

		static INTERRUPT_FUNC void recv_task_()
		{
			bool err = false;
			if(SCI::SSR.ORER()) {	///< 受信オーバランエラー状態確認
				SCI::SSR.ORER = 0;	///< 受信オーバランエラークリア
				err = true;
			}
			///< フレーミングエラー/パリティエラー状態確認
			if(SCI::SSR() & (SCI::SSR.FER.b() | SCI::SSR.PER.b())) {
				// エラーフラグの消去
				SCI::SSR.FER = 0;
				SCI::SSR.PER = 0;
				err = true;
			}
			volatile uint8_t data = SCI::RDR();
			if(!err) {
				recv_.put(data);
			}
		}

		static INTERRUPT_FUNC void send_task_()
		{
#if SIG_RX64M
			if(send_.length() > 0) {
				SCI::TDR = send_.get();
			}
			if(send_.length() == 0) {
				SCI::SCR.TIE = 0;
				send_stall_ = true;
			}
#else
			SCI::TDR = send_.get();
			if(send_.length() == 0) {
				SCI::SCR.TEIE = 0;
			}
#endif
		}

		void set_vector_(ICU::VECTOR rx_vec, ICU::VECTOR tx_vec) {
			if(level_) {
				set_interrupt_task(recv_task_, static_cast<uint32_t>(rx_vec));
				set_interrupt_task(send_task_, static_cast<uint32_t>(tx_vec));
			} else {
				set_interrupt_task(nullptr, static_cast<uint32_t>(rx_vec));
				set_interrupt_task(nullptr, static_cast<uint32_t>(tx_vec));
			}
		}

		void set_intr_() {
#if SIG_RX64M
			set_vector_(SCI::get_rx_vec(), SCI::get_tx_vec());
#else
			set_vector_(SCI::get_rx_vec(), SCI::get_te_vec());
#endif
			icu_mgr::set_level(SCI::get_peripheral(), level_);
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		sci_io() : level_(0), crlf_(true) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  ボーレートを設定して、SCI を有効にする @n
					※RX63T では、ポーリングはサポート外
			@param[in]	baud	ボーレート
			@param[in]	level	割り込みレベル（０の場合ポーリング）
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start(uint32_t baud, uint8_t level = 0) {
			send_stall_ = true;
#if SIG_RX63T
			if(level == 0) return false;
#endif
			crlf_ = true;
			level_ = level;

			SCI::SCR = 0x00;			// TE, RE disable.

			port_map::turn(SCI::get_peripheral());

			uint32_t brr = F_PCLKB / baud / 16;
			uint8_t cks = 0;
			while(brr > 512) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3) return false;
			bool abcs = true;
			if(brr > 256) { brr /= 2; abcs = false; }

			power_cfg::turn(SCI::get_peripheral());

			set_intr_();

			// 8 bits, 1 stop bit, no-parrity
			SCI::SMR = cks;
			SCI::SEMR.ABCS = abcs;
			if(brr) --brr;
			SCI::BRR = static_cast<uint8_t>(brr);

			if(level) {
				SCI::SCR = SCI::SCR.RIE.b() | SCI::SCR.TE.b() | SCI::SCR.RE.b();
			} else {
				SCI::SCR = SCI::SCR.TE.b() | SCI::SCR.RE.b();
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  通信速度を設定して、SPI を有効にする
			@param[in]	master	マスターモードの場合「true」
			@param[in]	bps	ビットレート
			@param[in]	level	割り込みレベル（０の場合ポーリング）
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start_spi(bool master, uint32_t bps, uint8_t level = 0)
		{
			send_stall_ = true;
			level_ = level;

			SCI::SCR = 0x00;			// TE, RE disable.

			uint32_t brr = F_PCLKB / bps / 2;
			if(brr & 1) { brr >>= 1; ++brr; }
			else { brr >>= 1; }
			uint8_t cks = 0;
			while(brr > 256) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3 || brr > 256) return false;

			power_cfg::turn(SCI::get_peripheral());

			set_intr_();

			// LSB(0), MSB(1) first
			SCI::SCMR.SDIR = 1;

			SCI::SIMR1.IICM = 0;
			SCI::SMR = cks | SCI::SMR.CM.b();
			SCI::SPMR.SSE = 0;		///< SS 端子制御しない「０」

			if(master) {
				SCI::SPMR.MSS = 0;
			} else {
				SCI::SPMR.MSS = 1;
			}

			// クロックタイミング種別選択
			SCI::SPMR.CKPOL = 0;
			SCI::SPMR.CKPH  = 0;

			if(brr) --brr;
brr = 1;
			SCI::BRR = static_cast<uint8_t>(brr);

			uint8_t scr = 0;
			if(master) {
				scr = SCI::SCR.CKE.b(0b01);
			} else {
				scr = SCI::SCR.CKE.b(0b10);
			}

			if(level_) {
				SCI::SCR = SCI::SCR.RIE.b() | SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
			} else {
				SCI::SCR = SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	CRLF 自動送出
			@param[in]	f	「false」なら無効
		 */
		//-----------------------------------------------------------------//
		void auto_crlf(bool f = true) { crlf_ = f; }

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 出力バッファのサイズを返す
			@return　バッファのサイズ
		 */
		//-----------------------------------------------------------------//
		uint32_t send_length() const {
			if(level_) {
				return send_.length();
			} else {
				return 0;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字出力
			@param[in]	ch	文字コード
		 */
		//-----------------------------------------------------------------//
		void putch(char ch) {
			if(crlf_ && ch == '\n') {
				putch('\r');
			}

			if(level_) {
				volatile bool b = SCI::SSR.ORER();
				if(b) {
					SCI::SSR.ORER = 0;
				}
				/// 送信バッファの容量が７／８の場合は、空になるまで待つ。
				if(send_.length() >= (send_.size() * 7 / 8)) {
					while(send_.length() != 0) sleep_();
				}
				send_.put(ch);
#if SIG_RX64M
				SCI::SCR.TIE = 0;
				if(send_stall_) {
					while(SCI::SSR.TEND() == 0) sleep_();
					SCI::TDR = send_.get();
					if(send_.length() > 0) {
						send_stall_ = false;
					}
				}
				SCI::SCR.TIE = !send_stall_;
#else
				if(SCI::SCR.TEIE() == 0) {
					SCI::SCR.TEIE = 1;
				}
#endif
			} else {
				while(SCI::SSR.TEND() == 0) sleep_();
				SCI::TDR = ch;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 入力文字数を取得
			@return	入力文字数
		 */
		//-----------------------------------------------------------------//
		uint32_t recv_length() {
			if(level_) {
				return recv_.length();
			} else {
				if(SCI::SSR.ORER()) {	///< 受信オーバランエラー状態確認
					SCI::SSR.ORER = 0;	///< 受信オーバランエラークリア
				}
#if defined(SIG_RX64M) || defined(SIG_RX24T)
				auto n = SCI::SSR.RDRF();
#else
				uint32_t n = 0;
#endif
				return n;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字入力
			@return 文字コード
		 */
		//-----------------------------------------------------------------//
		char getch() {
			if(level_) {
				while(recv_.length() == 0) sleep_();
				return recv_.get();
			} else {
				char ch;
				while(recv_length() == 0) sleep_();
				ch = SCI::RDR();	///< 受信データ読み出し
				return ch;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	uart文字列出力
			@param[in]	s	出力ストリング
		 */
		//-----------------------------------------------------------------//
		void puts(const char* s) {
			char ch;
			while((ch = *s++) != 0) {
				putch(ch);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送受信
			@param[in]	ch	送信データ
			@return	受信データ
		*/
		//-----------------------------------------------------------------//
		inline uint8_t xchg(uint8_t ch = 0xff)
		{
			if(level_) {
				return 0;
			} else {
				SCI::TDR = ch;
				while(recv_length() == 0) sleep_();
				return SCI::RDR();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル送信
			@param[in]	src	送信ソース
			@param[in]	cnt	送信サイズ
		*/
		//-----------------------------------------------------------------//
		void send(const void* src, uint16_t size)
		{
			const uint8_t* p = static_cast<const uint8_t*>(src);
			auto end = p + size;
			while(p < end) {
				xchg(*p);
				++p;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル受信
			@param[out]	dst	受信先
			@param[in]	cnt	受信サイズ
		*/
		//-----------------------------------------------------------------//
		void recv(void* dst, uint16_t size)
		{
			uint8_t* p = static_cast<uint8_t*>(dst);
			auto end = p + size;
			while(p < end) {
				*p = xchg();
				++p;
			}
		}
	};

	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		RECV_BUFF sci_io<SCI, RECV_BUFF, SEND_BUFF>::recv_;
	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		SEND_BUFF sci_io<SCI, RECV_BUFF, SEND_BUFF>::send_;
	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		volatile bool sci_io<SCI, RECV_BUFF, SEND_BUFF>::send_stall_;
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	R8C グループ・TimerRJ I/O 制御 @n
			Copyright 2015 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "common/vect.h"
#include "system.hpp"
#include "intr.hpp"
#include "timer_rj.hpp"

/// F_CLK はタイマー周期計算で必要で、設定が無いとエラーにします。
#ifndef F_CLK
#  error "trj_io.hpp requires F_CLK to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  TimerRJ I/O 制御クラス
		@param[in]	TASK 割り込み内で実行されるクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class TASK>
	class trj_io {

		static TASK task_;

	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  パルス計測モード
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class measurement {
			low_width,	///< Low レベル幅測定
			high_width,	///< High レベル幅測定
			freq,		///< 周波数測定
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  フィルタータイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class filter {
			none,		///< 無し
			f1 = 1,		///< f1 フィルター
			f8 = 2,		///< f8 フィルター
			f32 = 3,	///< f32 フィルター
		};

		static volatile uint8_t trjmr_;
		static volatile uint16_t trj_;

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  パルス出力用割り込み関数
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		static INTERRUPT_FUNC void itask_out() {
			TRJMR = trjmr_;
			TRJ = trj_;
			task_();
			volatile uint8_t v = TRJIR();
			TRJIR = 0x00;
		}

	private:
		bool set_freq_(uint32_t freq, uint16_t& trj, uint8_t& tck) const {
			uint32_t tn = F_CLK / (freq * 2);
			uint8_t cks = 0;
			while(tn > 65536) {
				tn >>= 1;
				++cks;
				if(cks == 2) {
					tn >>= 1;
				}
				if(cks >= 3) return false;
			}
			if(tn) --tn;
			else return false;

			static const uint8_t tbl_[3] = { 0, 3, 1 }; // 1/1, 1/2, 1/8
			tck = tbl_[cks];
			trj = tn;

			return true;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		trj_io() { }

		//-----------------------------------------------------------------//
		/*!
			@brief  パルス出力の開始（TRJIO/TRJO 端子から、パルスを出力）
			@param[in]	freq	周波数
			@param[in]	ir_lvl	割り込みレベル（０の場合割り込みを使用しない）
			@return 設定範囲を超えたら「false」
		*/
		//-----------------------------------------------------------------//
		bool pluse_out(uint32_t freq, uint8_t ir_lvl = 0) const {
			MSTCR.MSTTRJ = 0;  // モジュールスタンバイ解除

			TRJCR.TSTART = 0;  // カウンタを停止

			uint16_t trj;
			uint8_t tck;
			if(!set_freq_(freq, trj, tck)) {
				return false;
			}

			TRJMR = trjmr_ = TRJMR.TCK.b(tck) | TRJMR.TCKCUT.b(0) | TRJMR.TMOD.b(1);  // パルス出力モード
			TRJ = trj_ = trj;

			TRJIOC.TEDGSEL = 1;  // L から出力
			TRJIOC.TOPCR = 0;    // トグル出力

			ILVLB.B01 = ir_lvl;
			if(ir_lvl) {
				TRJIR = TRJIR.TRJIE.b(1);
			} else {
				TRJIR = TRJIR.TRJIE.b(0);
			}

			TRJCR.TSTART = 1;  // カウンタを開始

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  TRJ 出力周波数の再設定
			@param[in]	freq	周波数
			@return 設定範囲を超えたら「false」
		*/
		//-----------------------------------------------------------------//
		bool set_cycle(uint32_t freq) const {
			uint16_t trj;
			uint8_t tck;
			if(!set_freq_(freq, trj, tck)) {
				return false;
			}

			// パルス出力モード
			// TRJ = 0 だと、割り込みが発生しないので、ダイレクト出力する
			if(trj_ != 0 && ILVLB.B01()) {
				trjmr_ = TRJMR.TCK.b(tck) | TRJMR.TCKCUT.b(0) | TRJMR.TMOD.b(1);
				trj_ = trj;
				di();
				volatile uint8_t v = TRJIR();
				TRJIR = TRJIR.TRJIE.b(1);
				ei();
			} else {
				TRJMR = TRJMR.TCK.b(tck) | TRJMR.TCKCUT.b(0) | TRJMR.TMOD.b(1);
				TRJ = trj;
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  パルス計測の開始（TRJIO 端子から、パルスを入力）
			@param[in]	measur	パルス計測のモード
			@param[in]	fil		入力フィルター
			@param[in]	ir_lvl	割り込みレベル（０の場合割り込みを使用しない）
		*/
		//-----------------------------------------------------------------//
		void pluse_inp(measurement measur, filter fil = filter::none, uint8_t ir_lvl = 0) const {
			MSTCR.MSTTRJ = 0;  // モジュールスタンバイ解除

			TRJCR.TSTART = 0;  // カウンタを停止

			TRJIOC = TRJIOC.TIPF.b(static_cast<uint8_t>(fil)) | TRJIOC.TOPCR.b(1);
//			TRJMR  =

			TRJ = 0;

			TRJCR.TSTART = 1;  // カウンタを開始
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  TRJ カウント値を取得
			@return カウント値
		*/
		//-----------------------------------------------------------------//
		uint16_t get_count() const {
			return TRJ();
		}

	};

	// スタティック実態定義
	template<class TASK>
	volatile uint8_t trj_io<TASK>::trjmr_;
	template<class TASK>
	volatile uint16_t trj_io<TASK>::trj_;

}
<commit_msg>Update TimerJ I/O class<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	R8C グループ・TimerRJ I/O 制御 @n
			Copyright 2015 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "common/vect.h"
#include "system.hpp"
#include "intr.hpp"
#include "timer_rj.hpp"

/// F_CLK はタイマー周期計算で必要で、設定が無いとエラーにします。
#ifndef F_CLK
#  error "trj_io.hpp requires F_CLK to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  TimerRJ I/O 制御クラス
		@param[in]	TASK 割り込み内で実行されるクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class TASK>
	class trj_io {

		static TASK task_;

	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  パルス計測モード
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class measurement : uint8_t {
			low_width,	///< Low レベル幅測定
			high_width,	///< High レベル幅測定
			count,		///< パルス数測定
			freq,		///< 周期測定
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  フィルタータイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class filter : uint8_t {
			none,		///< 無し
			f1 = 1,		///< f1 フィルター
			f8 = 2,		///< f8 フィルター
			f32 = 3,	///< f32 フィルター
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  カウンターソース
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class source : uint8_t {
			f1 = 0,		///< f1
			f2 = 3,		///< f2
			f8 = 1,		///< f8
			fHOCO = 2	///< fHOCO
		};

		static volatile uint8_t trjmr_;
		static volatile uint16_t trj_;

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  パルス出力用割り込み関数
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		static INTERRUPT_FUNC void iout() {
			TRJMR = trjmr_;
			TRJ = trj_;
			volatile uint8_t v = TRJIR();
			TRJIR = 0x00;
			task_();
		}

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  パルス入力用割り込み関数
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		static INTERRUPT_FUNC void iinp() {
			uint8_t trjir = TRJIR.TRJIE.b(1);
			if(TRJCR.TEDGF()) {
				if(trjmr_ == 0) {
					trj_ = TRJ();
					trjir = 0x00;
				} else {
					--trjmr_;
				}
			}
			volatile uint8_t v = TRJIR();
			TRJIR = trjir;
 			task_();
		}

	private:
		bool set_freq_(uint32_t freq, uint16_t& trj, uint8_t& tck) const {
			uint32_t tn = F_CLK / (freq * 2);
			uint8_t cks = 0;
			while(tn > 65536) {
				tn >>= 1;
				++cks;
				if(cks == 2) {
					tn >>= 1;
				}
				if(cks >= 3) return false;
			}
			if(tn) --tn;
			else return false;

			static const uint8_t tbl_[3] = { 0, 3, 1 }; // 1/1, 1/2, 1/8
			tck = tbl_[cks];
			trj = tn;

			return true;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		trj_io() { }

		//-----------------------------------------------------------------//
		/*!
			@brief  パルス出力の開始（TRJIO/TRJO 端子から、パルスを出力）
			@param[in]	freq	周波数
			@param[in]	ir_lvl	割り込みレベル（０の場合割り込みを使用しない）
			@return 設定範囲を超えたら「false」
		*/
		//-----------------------------------------------------------------//
		bool pluse_out(uint32_t freq, uint8_t ir_lvl = 0) const {
			MSTCR.MSTTRJ = 0;  // モジュールスタンバイ解除

			TRJCR.TSTART = 0;  // カウンタを停止

			uint16_t trj;
			uint8_t tck;
			if(!set_freq_(freq, trj, tck)) {
				return false;
			}

			TRJMR = trjmr_ = TRJMR.TCK.b(tck) | TRJMR.TCKCUT.b(0) | TRJMR.TMOD.b(1);  // パルス出力モード
			TRJ = trj_ = trj;

			TRJIOC.TEDGSEL = 1;  // L から出力
			TRJIOC.TOPCR = 0;    // トグル出力

			ILVLB.B01 = ir_lvl;
			if(ir_lvl) {
				TRJIR = TRJIR.TRJIE.b(1);
			} else {
				TRJIR = TRJIR.TRJIE.b(0);
			}

			TRJCR.TSTART = 1;  // カウンタを開始

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  TRJ 出力周波数の再設定
			@param[in]	freq	周波数
			@return 設定範囲を超えたら「false」
		*/
		//-----------------------------------------------------------------//
		bool set_cycle(uint32_t freq) const {
			uint16_t trj;
			uint8_t tck;
			if(!set_freq_(freq, trj, tck)) {
				return false;
			}

			// パルス出力モード
			// TRJ = 0 だと、割り込みが発生しないので、直接設定する
			if(trj_ != 0 && ILVLB.B01()) {
				trjmr_ = TRJMR.TCK.b(tck) | TRJMR.TCKCUT.b(0) | TRJMR.TMOD.b(1);
				trj_ = trj;
				di();
				volatile uint8_t v = TRJIR();
				TRJIR = TRJIR.TRJIE.b(1);
				ei();
			} else {
				TRJMR = TRJMR.TCK.b(tck) | TRJMR.TCKCUT.b(0) | TRJMR.TMOD.b(1);
				TRJ = trj;
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  パルス計測の開始（TRJIO 端子から、パルスを入力）@n
					※VCOUT1 端子から入力する場合は、TRJIOSEL を設定する。
			@param[in]	measur	パルス計測のモード
			@param[in]	s		カウンターソース（countの場合は無効）
			@param[in]	ir_lvl	割り込みレベル（０の場合割り込みを使用しない）
		*/
		//-----------------------------------------------------------------//
		void pluse_inp(measurement measur, source s, uint8_t ir_lvl = 0) const {
			MSTCR.MSTTRJ = 0;  // モジュールスタンバイ解除

			TRJCR = 0x00;  // カウンタ停止

			bool f = TRJIOC.TEDGSEL();
			uint8_t md = 3;
			if(measur == measurement::low_width) {
				f = 0;
			} else if(measur == measurement::high_width) {
				f = 1;
			} else if(measur == measurement::count) {
				md = 2;
			} else if(measur == measurement::freq) {
				md = 4;
			}
			TRJIOC = TRJIOC.TEDGSEL.b(f) | TRJIOC.TIPF.b(0) | TRJIOC.TOPCR.b(0);
			TRJMR = TRJMR.TMOD.b(md) | TRJMR.TCK.b(static_cast<uint8_t>(s))
						   | TRJMR.TEDGPL.b(0) | TRJMR.TCKCUT.b(0);

			ILVLB.B01 = ir_lvl;
			if(ir_lvl) {
				TRJIR = TRJIR.TRJIE.b(1);
			} else {
				TRJIR = TRJIR.TRJIE.b(0);
			}

			trjmr_ = 2;
			TRJ = trj_ = 0xffff;
			TRJCR = TRJCR.TSTART.b(1);  // カウンタを開始、アンダーフロー・クリア
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  TRJ カウント値を取得（割り込み内で設定された値）
			@param[out]	count	カウント値
			@return アンダーフローの場合「false」
		*/
		//-----------------------------------------------------------------//
		bool get_count(uint16_t& count) const {
			if(ILVLB.B01()) {
				count = ~trj_;
			} else {
				count = ~TRJ();
			}
			return !TRJCR.TUNDF();
		}

	};

	// スタティック実態定義
	template<class TASK>
	volatile uint8_t trj_io<TASK>::trjmr_;
	template<class TASK>
	volatile uint16_t trj_io<TASK>::trj_;

}
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <kernel/elf.hpp>
#include <common>
#include <cassert>
#include <cstdio>
#include <string>
#include <unistd.h>
#include <info>
#include <vector>
#include "../../vmbuild/elf.h"

static const char* null_stringz = "(null)";
static const char* boot_stringz = "Bootloader area";
extern "C" char _ELF_START_;
static const uintptr_t ELF_START = reinterpret_cast<uintptr_t>(&_ELF_START_);

#define frp(N, ra)                                 \
  (__builtin_frame_address(N) != nullptr) &&       \
    (ra = __builtin_return_address(N)) != nullptr

extern "C" char *
__cxa_demangle(const char *name, char *buf, size_t *n, int *status);

template <typename N>
static std::string to_hex_string(N n)
{
  std::string buffer; buffer.reserve(64);
  snprintf((char*) buffer.data(), buffer.capacity(), "%#x", n);
  return buffer;
}

static Elf32_Ehdr& elf_header() {
  return *(Elf32_Ehdr*) ELF_START;
}

struct SymTab {
  Elf32_Sym* base;
  uint32_t   entries;
};
struct StrTab {
  const char* base;
  uint32_t    size;
};

class ElfTables
{
public:
  ElfTables() {}

  void set(void* syms, uint32_t entries, const char* string_table)
  {
    symtab.base    = (Elf32_Sym*) syms;
    symtab.entries = entries;
    strtab         = string_table;
  }

  func_offset getsym(Elf32_Addr addr)
  {
    // probably just a null pointer with ofs=addr
    if (UNLIKELY(addr < 0x7c00))
        return {null_stringz, 0, addr};
    // definitely in the bootloader
    if (UNLIKELY(addr < 0x7e00))
        return {boot_stringz, 0x7c00, addr - 0x7c00};
    // resolve manually from symtab
    auto* sym = getaddr(addr);
    // validate symbol address
    //assert(sym >= symtab.base && sym < symtab.base + symtab.entries);
    if (LIKELY(sym)) {
      auto base   = sym->st_value;
      auto offset = addr - base;
      // return string name for symbol
      return {demangle( sym_name(sym) ), base, offset};
    }
    // function or space not found
    return {to_hex_string(addr), addr, 0};
  }
  safe_func_offset getsym_safe(Elf32_Addr addr, char* buffer, size_t length)
  {
    // probably just a null pointer with ofs=addr
    if (addr < 0x7c00) return {null_stringz, 0, addr};
    // definitely in the bootloader
    if (addr < 0x7e00) return {boot_stringz, 0x7c00, addr - 0x7c00};
    // resolve manually from symtab
    auto* sym = getaddr(addr);
    if (sym) {
      auto base   = sym->st_value;
      auto offset = addr - base;
      // return string name for symbol
      return {demangle_safe( sym_name(sym), buffer, length ), base, offset};
    }
    // function or space not found
    snprintf(buffer, length, "%#x", addr);
    return {buffer, addr, 0};
  }

  Elf32_Addr getaddr(const std::string& name)
  {
    for (size_t i = 0; i < symtab.entries; i++)
    {
      auto& sym = symtab.base[i];
      //if (ELF32_ST_TYPE(sym.st_info) == STT_FUNC)
      if (demangle( sym_name(&sym) ) == name)
          return sym.st_value;
    }
    return 0;
  }
  Elf32_Sym* getaddr(Elf32_Addr addr)
  {
    for (size_t i = 0; i < symtab.entries; i++) {

      //if (ELF32_ST_TYPE(symtab.base[i].st_info) == STT_FUNC)
      if (addr >= symtab.base[i].st_value
      && (addr <  symtab.base[i].st_value + symtab.base[i].st_size))
          return &symtab.base[i];
    }
    return nullptr;
  }

  size_t end_of_file() const {
    auto& hdr = elf_header();
    return hdr.e_ehsize + (hdr.e_phnum * hdr.e_phentsize) + (hdr.e_shnum * hdr.e_shentsize);
  }

  const SymTab& get_symtab() const {
    return symtab;
  }

  const auto* get_strtab() const {
    return strtab;
  }

private:
  const char* sym_name(Elf32_Sym* sym) const {
    return &strtab[sym->st_name];
  }
  std::string demangle(const char* name) const
  {
    if (name[0] == '_') {
      int status;
      // internally, demangle just returns buf when status is ok
      auto* res = __cxa_demangle(name, nullptr, 0, &status);
      if (status == 0) {
        std::string result(res);
        std::free(res);
        return result;
      }
    }
    return std::string(name);
  }
  const char* demangle_safe(const char* name, char* buffer, size_t buflen) const
  {
    int status;
    // internally, demangle just returns buf when status is ok
    auto* res = __cxa_demangle(name, (char*) buffer, &buflen, &status);
    if (status) return name;
    return res;
  }

  SymTab      symtab;
  const char* strtab;
};
static ElfTables parser;

ElfTables& get_parser() {
  return parser;
}

size_t Elf::end_of_file() {
  return get_parser().end_of_file();
}
const char* Elf::get_strtab() {
  return get_parser().get_strtab();
}

func_offset Elf::resolve_symbol(uintptr_t addr)
{
  return get_parser().getsym(addr);
}
func_offset Elf::resolve_symbol(void* addr)
{
  return get_parser().getsym((uintptr_t) addr);
}

uintptr_t Elf::resolve_addr(uintptr_t addr)
{
  auto* sym = get_parser().getaddr(addr);
  if (sym) return sym->st_value;
  return addr;
}
uintptr_t Elf::resolve_addr(void* addr)
{
  auto* sym = get_parser().getaddr((uintptr_t) addr);
  if (sym) return sym->st_value;
  return (uintptr_t) addr;
}

safe_func_offset Elf::safe_resolve_symbol(void* addr, char* buffer, size_t length)
{
  return get_parser().getsym_safe((Elf32_Addr) addr, buffer, length);
}
uintptr_t Elf::resolve_name(const std::string& name)
{
  return get_parser().getaddr(name);
}

func_offset Elf::get_current_function()
{
  return resolve_symbol(__builtin_return_address(0));
}
std::vector<func_offset> Elf::get_functions()
{
  std::vector<func_offset> vec;
  #define ADD_TRACE(N, ra)                      \
      vec.push_back(Elf::resolve_symbol(ra));

  void* ra;
  if (frp(0, ra)) {
    ADD_TRACE(0, ra);
    if (frp(1, ra)) {
      ADD_TRACE(1, ra);
      if (frp(2, ra)) {
        ADD_TRACE(2, ra);
        if (frp(3, ra)) {
          ADD_TRACE(3, ra);
          if (frp(4, ra)) {
            ADD_TRACE(4, ra);
            if (frp(5, ra)) {
              ADD_TRACE(5, ra);
              if (frp(6, ra)) {
                ADD_TRACE(6, ra);
                if (frp(7, ra)) {
                  ADD_TRACE(7, ra);
                  if (frp(8, ra)) {
                    ADD_TRACE(8, ra);
  }}}}}}}}}
  return vec;
}

void print_backtrace()
{
  char _symbol_buffer[512];
  char _btrace_buffer[512];

  if (Elf::get_strtab() == NULL) {
    int len = snprintf(_btrace_buffer, sizeof(_btrace_buffer),
              "symtab or strtab is empty, indicating image may be stripped\n");
    write(1, _btrace_buffer, len);
  }

  #define PRINT_TRACE(N, ra) \
    auto symb = Elf::safe_resolve_symbol(                     \
                ra, _symbol_buffer, sizeof(_symbol_buffer));  \
    int len = snprintf(_btrace_buffer, sizeof(_btrace_buffer),\
             "[%d] %8x + 0x%.3x: %s\n", \
             N, symb.addr, symb.offset, symb.name);\
    write(1, _btrace_buffer, len);

  printf("\n");
  void* ra;
  if (frp(0, ra)) {
    PRINT_TRACE(0, ra);
    if (frp(1, ra)) {
      PRINT_TRACE(1, ra);
      if (frp(2, ra)) {
        PRINT_TRACE(2, ra);
        if (frp(3, ra)) {
          PRINT_TRACE(3, ra);
          if (frp(4, ra)) {
            PRINT_TRACE(4, ra);
            if (frp(5, ra)) {
              PRINT_TRACE(5, ra);
              if (frp(6, ra)) {
                PRINT_TRACE(6, ra);
                if (frp(7, ra)) {
                  PRINT_TRACE(7, ra);
                  if (frp(8, ra)) {
                    PRINT_TRACE(8, ra);
  }}}}}}}}}
}

void Elf::print_info()
{
  auto& hdr = elf_header();
  // program headers
  auto* phdr = (Elf32_Phdr*) (ELF_START + hdr.e_phoff);
  printf("program headers offs=%#x at phys %p\n", hdr.e_phoff, phdr);
  // section headers
  auto* shdr = (Elf32_Shdr*) (ELF_START + hdr.e_shoff);
  printf("section headers offs=%#x at phys %p\n", hdr.e_shoff, shdr);
  for (Elf32_Half i = 0; i < hdr.e_shnum; i++)
  {
    uintptr_t start = ELF_START + shdr[i].sh_offset;
    uintptr_t end   = start     + shdr[i].sh_size;
    printf("sh from %#x to %#x\n", start, end);
  }

}

extern "C"
void _print_elf_symbols()
{
  const auto& symtab = parser.get_symtab();
  const char* strtab = parser.get_strtab();

  for (size_t i = 0; i < symtab.entries; i++)
  {
    printf("%8x: %s\n", symtab.base[i].st_value, &strtab[symtab.base[i].st_name]);
  }
  printf("*** %u entries\n", symtab.entries);
}
extern "C"
void _validate_elf_symbols()
{
  const auto& symtab = parser.get_symtab();
  const char* strtab = parser.get_strtab();
  if (symtab.entries == 0 || strtab == nullptr) return;

  for (size_t i = 1; i < symtab.entries; i++)
  {
    if (symtab.base[i].st_value != 0) {
      assert(symtab.base[i].st_value > 0x2000);
      const char* string = &strtab[symtab.base[i].st_name];
      assert(strlen(string));
    }
  }
}

struct relocate_header {
  SymTab symtab;
  StrTab strtab;
};

extern "C"
int _get_elf_section_size(const void* location)
{
  auto& hdr = *(relocate_header*) location;
  return sizeof(relocate_header) + hdr.symtab.entries * sizeof(Elf32_Sym) + hdr.strtab.size;
}

extern "C"
void _move_elf_symbols(void* old_location, void* new_location)
{
  int size = _get_elf_section_size(old_location);
  memcpy(new_location, old_location, size);
  // update symbol info table
  auto* newhdr = (relocate_header*) new_location;
  const char* base = ((char*) newhdr) + sizeof(relocate_header);
  newhdr->symtab.base = (Elf32_Sym*) base;
  newhdr->strtab.base = &base[newhdr->symtab.entries * sizeof(Elf32_Sym)];
}

#include <malloc.h>
extern "C"
void* _relocate_to_heap(void* old_location)
{
  int total = _get_elf_section_size(old_location);
  void* heap_location = malloc(total);

  _move_elf_symbols(old_location, heap_location);
  return heap_location;
}

extern "C"
void _apply_parser_data(char* location)
{
  if (location) {
    auto& hdr = *(relocate_header*) location;
    // apply changes to the symbol parser from custom location
    parser.set(hdr.symtab.base, hdr.symtab.entries, hdr.strtab.base);
  }
  else {
    // symbols and strings are stripped out
    parser.set(nullptr, 0, nullptr);
  }
}
<commit_msg>elf: Fix broken to_hex_string<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <kernel/elf.hpp>
#include <common>
#include <cassert>
#include <cstdio>
#include <string>
#include <unistd.h>
#include <info>
#include <vector>
#include "../../vmbuild/elf.h"

static const char* null_stringz = "(null)";
static const char* boot_stringz = "Bootloader area";
extern "C" char _ELF_START_;
static const uintptr_t ELF_START = reinterpret_cast<uintptr_t>(&_ELF_START_);

#define frp(N, ra)                                 \
  (__builtin_frame_address(N) != nullptr) &&       \
    (ra = __builtin_return_address(N)) != nullptr

extern "C" char *
__cxa_demangle(const char *name, char *buf, size_t *n, int *status);

template <typename N>
static std::string to_hex_string(N n)
{
  char buffer[16];
  int len = snprintf(buffer, sizeof(buffer), "%#x", n);
  return std::string(buffer, len);
}

static Elf32_Ehdr& elf_header() {
  return *(Elf32_Ehdr*) ELF_START;
}

struct SymTab {
  Elf32_Sym* base;
  uint32_t   entries;
};
struct StrTab {
  const char* base;
  uint32_t    size;
};

class ElfTables
{
public:
  ElfTables() {}

  void set(void* syms, uint32_t entries, const char* string_table)
  {
    symtab.base    = (Elf32_Sym*) syms;
    symtab.entries = entries;
    strtab         = string_table;
  }

  func_offset getsym(Elf32_Addr addr)
  {
    // probably just a null pointer with ofs=addr
    if (UNLIKELY(addr < 0x7c00))
        return {null_stringz, 0, addr};
    // definitely in the bootloader
    if (UNLIKELY(addr < 0x7e00))
        return {boot_stringz, 0x7c00, addr - 0x7c00};
    // resolve manually from symtab
    auto* sym = getaddr(addr);
    // validate symbol address
    //assert(sym >= symtab.base && sym < symtab.base + symtab.entries);
    if (LIKELY(sym)) {
      auto base   = sym->st_value;
      auto offset = addr - base;
      // return string name for symbol
      return {demangle( sym_name(sym) ), base, offset};
    }
    // function or space not found
    return {to_hex_string(addr), addr, 0};
  }
  safe_func_offset getsym_safe(Elf32_Addr addr, char* buffer, size_t length)
  {
    // probably just a null pointer with ofs=addr
    if (addr < 0x7c00) return {null_stringz, 0, addr};
    // definitely in the bootloader
    if (addr < 0x7e00) return {boot_stringz, 0x7c00, addr - 0x7c00};
    // resolve manually from symtab
    auto* sym = getaddr(addr);
    if (LIKELY(sym)) {
      auto base   = sym->st_value;
      auto offset = addr - base;
      // return string name for symbol
      return {demangle_safe( sym_name(sym), buffer, length ), base, offset};
    }
    // function or space not found
    snprintf(buffer, length, "0x%08x", addr);
    return {buffer, addr, 0};
  }

  Elf32_Addr getaddr(const std::string& name)
  {
    for (size_t i = 0; i < symtab.entries; i++)
    {
      auto& sym = symtab.base[i];
      //if (ELF32_ST_TYPE(sym.st_info) == STT_FUNC)
      if (demangle( sym_name(&sym) ) == name)
          return sym.st_value;
    }
    return 0;
  }
  Elf32_Sym* getaddr(Elf32_Addr addr)
  {
    for (size_t i = 0; i < symtab.entries; i++) {

      //if (ELF32_ST_TYPE(symtab.base[i].st_info) == STT_FUNC)
      if (addr >= symtab.base[i].st_value
      && (addr <  symtab.base[i].st_value + symtab.base[i].st_size))
          return &symtab.base[i];
    }
    return nullptr;
  }

  size_t end_of_file() const {
    auto& hdr = elf_header();
    return hdr.e_ehsize + (hdr.e_phnum * hdr.e_phentsize) + (hdr.e_shnum * hdr.e_shentsize);
  }

  const SymTab& get_symtab() const {
    return symtab;
  }

  const auto* get_strtab() const {
    return strtab;
  }

private:
  const char* sym_name(Elf32_Sym* sym) const {
    return &strtab[sym->st_name];
  }
  std::string demangle(const char* name) const
  {
    if (name[0] == '_') {
      int status;
      // internally, demangle just returns buf when status is ok
      auto* res = __cxa_demangle(name, nullptr, 0, &status);
      if (status == 0) {
        std::string result(res);
        std::free(res);
        return result;
      }
    }
    return std::string(name);
  }
  const char* demangle_safe(const char* name, char* buffer, size_t buflen) const
  {
    int status;
    // internally, demangle just returns buf when status is ok
    auto* res = __cxa_demangle(name, (char*) buffer, &buflen, &status);
    if (status) return name;
    return res;
  }

  SymTab      symtab;
  const char* strtab;
};
static ElfTables parser;

ElfTables& get_parser() {
  return parser;
}

size_t Elf::end_of_file() {
  return get_parser().end_of_file();
}
const char* Elf::get_strtab() {
  return get_parser().get_strtab();
}

func_offset Elf::resolve_symbol(uintptr_t addr)
{
  return get_parser().getsym(addr);
}
func_offset Elf::resolve_symbol(void* addr)
{
  return get_parser().getsym((uintptr_t) addr);
}

uintptr_t Elf::resolve_addr(uintptr_t addr)
{
  auto* sym = get_parser().getaddr(addr);
  if (sym) return sym->st_value;
  return addr;
}
uintptr_t Elf::resolve_addr(void* addr)
{
  auto* sym = get_parser().getaddr((uintptr_t) addr);
  if (sym) return sym->st_value;
  return (uintptr_t) addr;
}

safe_func_offset Elf::safe_resolve_symbol(void* addr, char* buffer, size_t length)
{
  return get_parser().getsym_safe((Elf32_Addr) addr, buffer, length);
}
uintptr_t Elf::resolve_name(const std::string& name)
{
  return get_parser().getaddr(name);
}

func_offset Elf::get_current_function()
{
  return resolve_symbol(__builtin_return_address(0));
}
std::vector<func_offset> Elf::get_functions()
{
  std::vector<func_offset> vec;
  #define ADD_TRACE(N, ra)                      \
      vec.push_back(Elf::resolve_symbol(ra));

  void* ra;
  if (frp(0, ra)) {
    ADD_TRACE(0, ra);
    if (frp(1, ra)) {
      ADD_TRACE(1, ra);
      if (frp(2, ra)) {
        ADD_TRACE(2, ra);
        if (frp(3, ra)) {
          ADD_TRACE(3, ra);
          if (frp(4, ra)) {
            ADD_TRACE(4, ra);
            if (frp(5, ra)) {
              ADD_TRACE(5, ra);
              if (frp(6, ra)) {
                ADD_TRACE(6, ra);
                if (frp(7, ra)) {
                  ADD_TRACE(7, ra);
                  if (frp(8, ra)) {
                    ADD_TRACE(8, ra);
  }}}}}}}}}
  return vec;
}

void print_backtrace()
{
  char _symbol_buffer[512];
  char _btrace_buffer[512];

  if (Elf::get_strtab() == NULL) {
    int len = snprintf(_btrace_buffer, sizeof(_btrace_buffer),
              "symtab or strtab is empty, indicating image may be stripped\n");
    write(1, _btrace_buffer, len);
  }

  #define PRINT_TRACE(N, ra) \
    auto symb = Elf::safe_resolve_symbol(                     \
                ra, _symbol_buffer, sizeof(_symbol_buffer));  \
    int len = snprintf(_btrace_buffer, sizeof(_btrace_buffer),\
             "[%d] %8x + 0x%.3x: %s\n", \
             N, symb.addr, symb.offset, symb.name);\
    write(1, _btrace_buffer, len);

  printf("\n");
  void* ra;
  if (frp(0, ra)) {
    PRINT_TRACE(0, ra);
    if (frp(1, ra)) {
      PRINT_TRACE(1, ra);
      if (frp(2, ra)) {
        PRINT_TRACE(2, ra);
        if (frp(3, ra)) {
          PRINT_TRACE(3, ra);
          if (frp(4, ra)) {
            PRINT_TRACE(4, ra);
            if (frp(5, ra)) {
              PRINT_TRACE(5, ra);
              if (frp(6, ra)) {
                PRINT_TRACE(6, ra);
                if (frp(7, ra)) {
                  PRINT_TRACE(7, ra);
                  if (frp(8, ra)) {
                    PRINT_TRACE(8, ra);
  }}}}}}}}}
}

void Elf::print_info()
{
  auto& hdr = elf_header();
  // program headers
  auto* phdr = (Elf32_Phdr*) (ELF_START + hdr.e_phoff);
  printf("program headers offs=%#x at phys %p\n", hdr.e_phoff, phdr);
  // section headers
  auto* shdr = (Elf32_Shdr*) (ELF_START + hdr.e_shoff);
  printf("section headers offs=%#x at phys %p\n", hdr.e_shoff, shdr);
  for (Elf32_Half i = 0; i < hdr.e_shnum; i++)
  {
    uintptr_t start = ELF_START + shdr[i].sh_offset;
    uintptr_t end   = start     + shdr[i].sh_size;
    printf("sh from %#x to %#x\n", start, end);
  }

}

extern "C"
void _print_elf_symbols()
{
  const auto& symtab = parser.get_symtab();
  const char* strtab = parser.get_strtab();

  for (size_t i = 0; i < symtab.entries; i++)
  {
    printf("%8x: %s\n", symtab.base[i].st_value, &strtab[symtab.base[i].st_name]);
  }
  printf("*** %u entries\n", symtab.entries);
}
extern "C"
void _validate_elf_symbols()
{
  const auto& symtab = parser.get_symtab();
  const char* strtab = parser.get_strtab();
  if (symtab.entries == 0 || strtab == nullptr) return;

  for (size_t i = 1; i < symtab.entries; i++)
  {
    if (symtab.base[i].st_value != 0) {
      assert(symtab.base[i].st_value > 0x2000);
      const char* string = &strtab[symtab.base[i].st_name];
      assert(strlen(string));
    }
  }
}

struct relocate_header {
  SymTab symtab;
  StrTab strtab;
};

extern "C"
int _get_elf_section_size(const void* location)
{
  auto& hdr = *(relocate_header*) location;
  return sizeof(relocate_header) + hdr.symtab.entries * sizeof(Elf32_Sym) + hdr.strtab.size;
}

extern "C"
void _move_elf_symbols(void* old_location, void* new_location)
{
  int size = _get_elf_section_size(old_location);
  memcpy(new_location, old_location, size);
  // update symbol info table
  auto* newhdr = (relocate_header*) new_location;
  const char* base = ((char*) newhdr) + sizeof(relocate_header);
  newhdr->symtab.base = (Elf32_Sym*) base;
  newhdr->strtab.base = &base[newhdr->symtab.entries * sizeof(Elf32_Sym)];
}

#include <malloc.h>
extern "C"
void* _relocate_to_heap(void* old_location)
{
  int total = _get_elf_section_size(old_location);
  void* heap_location = malloc(total);

  _move_elf_symbols(old_location, heap_location);
  return heap_location;
}

extern "C"
void _apply_parser_data(char* location)
{
  if (location) {
    auto& hdr = *(relocate_header*) location;
    // apply changes to the symbol parser from custom location
    parser.set(hdr.symtab.base, hdr.symtab.entries, hdr.strtab.base);
  }
  else {
    // symbols and strings are stripped out
    parser.set(nullptr, 0, nullptr);
  }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <algorithm>
#include <thread>
#include <cmath>

#include <boost/lexical_cast.hpp>

#include "Point.hpp"
#include "Function.hpp"
#include "SymbolicRegressionSolver.hpp"
#include "Config.hpp"

#define OPTIMISE_CONFIG

int amountOfSimulationsToPerform = 1;
SymbolicRegressionSolver::Config config{};
Function fn{parse("+ 1 x").statement, "x"};
int initialPoint = -10;
int endPoint = 10;
int stepSize = 1;

std::istream& operator>>(std::istream& is, SymbolicRegressionSolver::Config& config);
std::ostream& operator<<(std::ostream& os, const SymbolicRegressionSolver::Config& config);

void parseArguments(int argc, char *argv[]);
void printValidFlags()
{
    std::cout << "-c <configuration-file> (TODO)\n";
    std::cout << "-f <function>\n";
    std::cout << "-i <initial-point>\n";
    std::cout << "-e <end-point>\n";
    std::cout << "-s <step size>\n";
    std::cout << "-r <amount of times to redo simulation>\n";
}

struct Result
{
    Result(double var, double average, size_t totalSolutions) : var(var), average(average), totalSolutions(totalSolutions) { }
    double var;
    double average;
    size_t totalSolutions;
};

constexpr const int AMOUNT_OF_THREADS = 4;
std::vector<Result> solutions[AMOUNT_OF_THREADS];

template <class T>
void optimiseConfig(size_t id, const PointList& points, const T& start, const T& end, const T& step)
{
    SymbolicRegressionSolver solver{config, points};
    auto& variableToModify = solver.config().keepPercentage;

#ifdef OPTIMISE_CONFIG
    for(variableToModify = start; variableToModify <= end; variableToModify += step)
    {
        double currentAverage = 0;
        size_t totalSolutions = 0;
#endif // OPTIMISE_CONFIG

        for(int i = 0; i < amountOfSimulationsToPerform; ++i)
        {
            auto solutions = solver.solve();

#ifndef OPTIMISE_CONFIG
            for(auto& solution : solutions)
            {
                std::cout << solver.currentGeneration() << ",";
                std::cout << solution.fitnessLevel << ",";
                std::cout << solution.mutated << ",";
                std::cout << solution.mated << '\n';
            }
#else
            totalSolutions += solutions.size();
            currentAverage += solver.currentGeneration();
#endif // OPTIMISE_CONFIG

            solver.reset();
        }

#ifdef OPTIMISE_CONFIG
		currentAverage /= amountOfSimulationsToPerform;

        solutions[id].emplace_back(variableToModify, currentAverage, totalSolutions);
    }
#endif // OPTIMISE_CONFIG
}

int main(int argc, char *argv[])
{
    parseArguments(argc, argv);

#ifdef VERBOSE_LOG
    std::clog << "function: " << fn << '\n';
    std::clog << "initial point: " << initialPoint << '\n';
    std::clog << "end point: " << endPoint << '\n';
    std::clog << "step size: " << stepSize << '\n';
#endif // VERBOSE_LOG

    std::vector<Point> points;
    points.reserve((endPoint - initialPoint)/stepSize);

    VariableMap map;
    for(int i = initialPoint; i <= endPoint; i += stepSize)
    {
        points.emplace_back(i, fn(map, i));
    }

    std::vector<std::thread> threads;
    for(int i = 0; i < AMOUNT_OF_THREADS; ++i)
    {
        constexpr double STEP_SIZE = 0.01;
        double start = i * 1.0 / AMOUNT_OF_THREADS;
        double end = (i + 1) * 1.0 / AMOUNT_OF_THREADS;

        threads.emplace_back([=]() { optimiseConfig(i, points, start, end,  STEP_SIZE); } );
    }

    for(auto& t : threads)
    {
        t.join();
    }

    std::vector<Result> sols;
    for(auto& sol : solutions)
    {
        //std::cout << "size of sol is: " << sol.size() << '\n';
        sols.insert(sols.end(), sol.begin(), sol.end());
    }
    std::sort(sols.begin(), sols.end(), [](const Result& r1, const Result& r2) { return r1.var < r2.var; });

    for(auto& sol : sols)
    {
        std::cout << sol.var << ", " << sol.average << ", " << sol.totalSolutions << '\n';
    }

    return 0;
}

void parseArguments(int argc, char *argv[])
{
    for(int i = 1; i < argc; ++i)
    {
        auto command = argv[i];
        auto commandSize = strlen(command);
        if(command[0] != '-')
        {
            std::cout << "Invalid format: " << command << ".\n";
            std::cout << "Flags must be prefixed with \"-\" (without quotes).\n";
            std::exit(-2);
            break;
        }

        if(commandSize == 1 || commandSize > 2)
        {
            std::cout << "Invalid flag: \"" << command << "\"\n";
            printValidFlags();
            std::exit(-5);
        }

        if(i + 1 >= argc)
        {
            std::cout << "please provide info with a flag...\n";
            printValidFlags();
            std::exit(-6);
        }

        switch(command[1])
        {
            // assign function
            case 'f':
                {
                    std::string functionAsString;
                    for(int j = i + 1; j < argc && argv[j][0] != '-'; ++j, ++i)
                    {
                        functionAsString += argv[j];
                    }
                    fn = parse(functionAsString).statement;
                }
                break;
            case 'i':
                {
                    std::string str = argv[++i];
                    initialPoint = boost::lexical_cast<int>(str);
                }
                break;
            case 'e':
                {
                    std::string str = argv[++i];
                    endPoint = boost::lexical_cast<int>(str);
                }
                break;
            case 's':
                {
                    std::string str = argv[++i];
                    stepSize = boost::lexical_cast<int>(str);
                }
                break;
            case 'r':
                {
                    std::string str = argv[++i];
                    amountOfSimulationsToPerform = boost::lexical_cast<int>(str);
                }
                break;
            case 'c':
                {
                    try
                    {
                        std::string filepath = argv[++i];
                        std::ifstream file;
                        file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
                        file.open(filepath);
                        file >> config; // read the config
                    }
                    catch(boost::bad_lexical_cast& e)
                    {
                        std::cerr << e.what();
                        std::exit(5);
                    }
                    catch(std::exception& e)
                    {
                        std::cerr << e.what();
                        std::exit(6);
                    }
                }
                break;
            default:
                std::cout << "Invalid flag\n";
                printValidFlags();
                std::exit(-4);
                break;
        }
    }
}

namespace
{
std::string obtainValue(const std::string& line)
{
    return std::string(line.begin() + line.find_last_of('=') + 1, line.end());
}

template <class T>
void read(std::string& buffer, std::istream& is, T& value)
{
    std::getline(is, buffer);
    auto stringValue = obtainValue(buffer);
    stringValue.erase(std::remove_if(stringValue.begin(), stringValue.end(), [](char c) { return std::isspace(c); }), stringValue.end());
    value = boost::lexical_cast<T>(stringValue);
}
}

std::istream& operator>>(std::istream& is, SymbolicRegressionSolver::Config& config)
{
    std::string buffer;

    read(buffer, is, config.initialPopulation);
    read(buffer, is, config.maxGenerations);
    read(buffer, is, config.initialMaxDepth);
    read(buffer, is, config.maxSolutionDepth);
    read(buffer, is, config.keepPercentage);
    read(buffer, is, config.mutationPercent);
    read(buffer, is, config.matePercent);

    // have to do this separately for const dist
    int a, b;
    read(buffer, is, a);
    read(buffer, is, b);

    config.constantDist = decltype(config.constantDist){a, b};

    read(buffer, is, config.solutionCriterea);
    read(buffer, is, config.chanceToChangeConstant);
    read(buffer, is, config.chanceToChangeVar);

    int nearestNeighbour = 0;
    read(buffer, is, nearestNeighbour);
    config.nearestNeighbourOption = static_cast<decltype(config.nearestNeighbourOption)>(nearestNeighbour);

    read(buffer, is, config.chanceToUseNearestNeighbour);
    read(buffer, is, config.stepSize);

    int refillOption = 0;
    read(buffer, is, refillOption);
    config.populationRefillOption = static_cast<decltype(config.populationRefillOption)>(refillOption);

    return is;
}
<commit_msg>Add MUTATE_MATE macro which does mutation/mating optimisation as a pair<commit_after>#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <algorithm>
#include <thread>
#include <cmath>

#include <boost/lexical_cast.hpp>

#include "Point.hpp"
#include "Function.hpp"
#include "SymbolicRegressionSolver.hpp"
#include "Config.hpp"

#define OPTIMISE_CONFIG

int amountOfSimulationsToPerform = 1;
SymbolicRegressionSolver::Config config{};
Function fn{parse("+ 1 x").statement, "x"};
int initialPoint = -10;
int endPoint = 10;
int stepSize = 1;

std::istream& operator>>(std::istream& is, SymbolicRegressionSolver::Config& config);
std::ostream& operator<<(std::ostream& os, const SymbolicRegressionSolver::Config& config);

void parseArguments(int argc, char *argv[]);
void printValidFlags()
{
    std::cout << "-c <configuration-file> (TODO)\n";
    std::cout << "-f <function>\n";
    std::cout << "-i <initial-point>\n";
    std::cout << "-e <end-point>\n";
    std::cout << "-s <step size>\n";
    std::cout << "-r <amount of times to redo simulation>\n";
}

#define MUTATE_MATE

struct Result
{
    Result(double var, double average, size_t totalSolutions) : var(var), average(average), totalSolutions(totalSolutions) { }
    Result(double var, double var2, double average, size_t totalSolutions) : var(var), var2(var2), average(average), totalSolutions(totalSolutions) { }
    double var;
    double var2;
    double average;
    size_t totalSolutions;
};

constexpr const int AMOUNT_OF_THREADS = 4;
std::vector<Result> solutions[AMOUNT_OF_THREADS];

template <class T>
void optimiseConfig(size_t id, const PointList& points, const T& start, const T& end, const T& step)
{
    SymbolicRegressionSolver solver{config, points};
#ifndef MUTATE_MATE
    auto& variableToModify = solver.config().keepPercentage;
#else
    auto& variableToModify = solver.config().matePercent;
#endif

#ifdef OPTIMISE_CONFIG
#ifdef MUTATE_MATE
    auto& var2 = solver.config().mutationPercent;
    for(var2 = start; var2 <= end; var2 += step)
#endif
#ifndef MUTATE_MATE
    for(variableToModify = start; variableToModify <= end; variableToModify += step)
#else
    for(variableToModify = 0; variableToModify <= 1; variableToModify += step)
#endif
    {
        double currentAverage = 0;
        size_t totalSolutions = 0;
#endif // OPTIMISE_CONFIG

        for(int i = 0; i < amountOfSimulationsToPerform; ++i)
        {
            auto solutions = solver.solve();

#ifndef OPTIMISE_CONFIG
            for(auto& solution : solutions)
            {
                std::cout << solver.currentGeneration() << ",";
                std::cout << solution.fitnessLevel << ",";
                std::cout << solution.mutated << ",";
                std::cout << solution.mated << '\n';
            }
#else
            totalSolutions += solutions.size();
            currentAverage += solver.currentGeneration();
#endif // OPTIMISE_CONFIG

            solver.reset();
        }

#ifdef OPTIMISE_CONFIG
		currentAverage /= amountOfSimulationsToPerform;

#ifndef MUTATE_MATE
        solutions[id].emplace_back(variableToModify, currentAverage, totalSolutions);
#else
        solutions[id].emplace_back(var2, variableToModify, currentAverage, totalSolutions);
#endif
    }
#endif // OPTIMISE_CONFIG
}

int main(int argc, char *argv[])
{
    parseArguments(argc, argv);

#ifdef VERBOSE_LOG
    std::clog << "function: " << fn << '\n';
    std::clog << "initial point: " << initialPoint << '\n';
    std::clog << "end point: " << endPoint << '\n';
    std::clog << "step size: " << stepSize << '\n';
#endif // VERBOSE_LOG

    std::vector<Point> points;
    points.reserve((endPoint - initialPoint)/stepSize);

    VariableMap map;
    for(int i = initialPoint; i <= endPoint; i += stepSize)
    {
        points.emplace_back(i, fn(map, i));
    }

    std::vector<std::thread> threads;
    for(int i = 0; i < AMOUNT_OF_THREADS; ++i)
    {
        constexpr double STEP_SIZE = 0.05;
        double start = i * 1.0 / AMOUNT_OF_THREADS;
        double end = (i + 1) * 1.0 / AMOUNT_OF_THREADS;

        threads.emplace_back([=]() { optimiseConfig(i, points, start, end,  STEP_SIZE); } );
    }

    for(auto& t : threads)
    {
        t.join();
    }

    std::vector<Result> sols;
    for(auto& sol : solutions)
    {
        //std::cout << "size of sol is: " << sol.size() << '\n';
        sols.insert(sols.end(), sol.begin(), sol.end());
    }
    std::sort(sols.begin(), sols.end(), [](const Result& r1, const Result& r2) { return r1.var < r2.var; });

    for(auto& sol : sols)
    {
#ifndef MUTATE_MATE
        std::cout << sol.var << ", " << sol.average << ", " << sol.totalSolutions << '\n';
#else
        std::cout << sol.var << ", " << sol.var2 << ", " << sol.average << ", " << sol.totalSolutions << '\n';
#endif // MUTATE_MATE
    }

    return 0;
}

void parseArguments(int argc, char *argv[])
{
    for(int i = 1; i < argc; ++i)
    {
        auto command = argv[i];
        auto commandSize = strlen(command);
        if(command[0] != '-')
        {
            std::cout << "Invalid format: " << command << ".\n";
            std::cout << "Flags must be prefixed with \"-\" (without quotes).\n";
            std::exit(-2);
            break;
        }

        if(commandSize == 1 || commandSize > 2)
        {
            std::cout << "Invalid flag: \"" << command << "\"\n";
            printValidFlags();
            std::exit(-5);
        }

        if(i + 1 >= argc)
        {
            std::cout << "please provide info with a flag...\n";
            printValidFlags();
            std::exit(-6);
        }

        switch(command[1])
        {
            // assign function
            case 'f':
                {
                    std::string functionAsString;
                    for(int j = i + 1; j < argc && argv[j][0] != '-'; ++j, ++i)
                    {
                        functionAsString += argv[j];
                    }
                    fn = parse(functionAsString).statement;
                }
                break;
            case 'i':
                {
                    std::string str = argv[++i];
                    initialPoint = boost::lexical_cast<int>(str);
                }
                break;
            case 'e':
                {
                    std::string str = argv[++i];
                    endPoint = boost::lexical_cast<int>(str);
                }
                break;
            case 's':
                {
                    std::string str = argv[++i];
                    stepSize = boost::lexical_cast<int>(str);
                }
                break;
            case 'r':
                {
                    std::string str = argv[++i];
                    amountOfSimulationsToPerform = boost::lexical_cast<int>(str);
                }
                break;
            case 'c':
                {
                    try
                    {
                        std::string filepath = argv[++i];
                        std::ifstream file;
                        file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
                        file.open(filepath);
                        file >> config; // read the config
                    }
                    catch(boost::bad_lexical_cast& e)
                    {
                        std::cerr << e.what();
                        std::exit(5);
                    }
                    catch(std::exception& e)
                    {
                        std::cerr << e.what();
                        std::exit(6);
                    }
                }
                break;
            default:
                std::cout << "Invalid flag\n";
                printValidFlags();
                std::exit(-4);
                break;
        }
    }
}

namespace
{
std::string obtainValue(const std::string& line)
{
    return std::string(line.begin() + line.find_last_of('=') + 1, line.end());
}

template <class T>
void read(std::string& buffer, std::istream& is, T& value)
{
    std::getline(is, buffer);
    auto stringValue = obtainValue(buffer);
    stringValue.erase(std::remove_if(stringValue.begin(), stringValue.end(), [](char c) { return std::isspace(c); }), stringValue.end());
    value = boost::lexical_cast<T>(stringValue);
}
}

std::istream& operator>>(std::istream& is, SymbolicRegressionSolver::Config& config)
{
    std::string buffer;

    read(buffer, is, config.initialPopulation);
    read(buffer, is, config.maxGenerations);
    read(buffer, is, config.initialMaxDepth);
    read(buffer, is, config.maxSolutionDepth);
    read(buffer, is, config.keepPercentage);
    read(buffer, is, config.mutationPercent);
    read(buffer, is, config.matePercent);

    // have to do this separately for const dist
    int a, b;
    read(buffer, is, a);
    read(buffer, is, b);

    config.constantDist = decltype(config.constantDist){a, b};

    read(buffer, is, config.solutionCriterea);
    read(buffer, is, config.chanceToChangeConstant);
    read(buffer, is, config.chanceToChangeVar);

    int nearestNeighbour = 0;
    read(buffer, is, nearestNeighbour);
    config.nearestNeighbourOption = static_cast<decltype(config.nearestNeighbourOption)>(nearestNeighbour);

    read(buffer, is, config.chanceToUseNearestNeighbour);
    read(buffer, is, config.stepSize);

    int refillOption = 0;
    read(buffer, is, refillOption);
    config.populationRefillOption = static_cast<decltype(config.populationRefillOption)>(refillOption);

    return is;
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2020.  All rights reserved
 */
#ifndef _Stroika_Foundation_Containers_Collection_inl_
#define _Stroika_Foundation_Containers_Collection_inl_

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */

#include "../Debug/Assertions.h"

#include "Factory/Collection_Factory.h"

namespace Stroika::Foundation::Containers {

    /*
     ********************************************************************************
     ******************************** Collection<T> *********************************
     ********************************************************************************
     */
    template <typename T>
    inline Collection<T>::Collection ()
        : inherited (Factory::Collection_Factory<T>{}())
    {
        _AssertRepValidType ();
    }
    template <typename T>
    template <typename COPY_FROM_ITERATOR_OF_ADDABLE>
    inline Collection<T>::Collection (COPY_FROM_ITERATOR_OF_ADDABLE start, COPY_FROM_ITERATOR_OF_ADDABLE end)
        : Collection{}
    {
        AddAll (start, end);
        _AssertRepValidType ();
    }
    template <typename T>
    inline Collection<T>::Collection (const _CollectionRepSharedPtr& src) noexcept
        : inherited{src}
    {
        RequireNotNull (src);
        _AssertRepValidType ();
    }
    template <typename T>
    inline Collection<T>::Collection (_CollectionRepSharedPtr&& src) noexcept
        : inherited (RequireNotNull (src), move (src)))
    {
        _AssertRepValidType ();
    }
    template <typename T>
    inline Collection<T>::Collection (const initializer_list<T>& src)
        : Collection{}
    {
        AddAll (src);
        _AssertRepValidType ();
    }
    template <typename T>
    template <typename CONTAINER_OF_ADDABLE, enable_if_t<Configuration::IsIterableOfT_v<CONTAINER_OF_ADDABLE, T> and not is_base_of_v<Collection<T>, Configuration::remove_cvref_t<CONTAINER_OF_ADDABLE>>>*>
    inline Collection<T>::Collection (CONTAINER_OF_ADDABLE&& src)
        : Collection{}
    {
        AddAll (forward<CONTAINER_OF_ADDABLE> (src));
        _AssertRepValidType ();
    }
#if qDebug
    template <typename T>
    Collection<T>::~Collection ()
    {
        if (this->_GetSharingState () != Memory::SharedByValue_State::eNull) {
            // SharingState can be NULL because of MOVE semantics
            _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().AssertNoIteratorsReferenceOwner (this);
        }
    }
#endif
    template <typename T>
    template <typename EQUALS_COMPARER>
    bool Collection<T>::Contains (ArgByValueType<T> item, const EQUALS_COMPARER& equalsComparer) const
    {
        for (auto&& i : *this) {
            if (equalsComparer (i, item)) {
                return true;
            }
        }
        return false;
    }
    template <typename T>
    template <typename COPY_FROM_ITERATOR_OF_ADDABLE>
    void Collection<T>::AddAll (COPY_FROM_ITERATOR_OF_ADDABLE start, COPY_FROM_ITERATOR_OF_ADDABLE end)
    {
        _SafeReadWriteRepAccessor<_IRep> tmp{this};
        for (auto&& i = start; i != end; ++i) {
            tmp._GetWriteableRep ().Add (*i);
        }
    }
    template <typename T>
    template <typename CONTAINER_OF_ADDABLE, enable_if_t<Configuration::IsIterableOfT_v<CONTAINER_OF_ADDABLE, T>>*>
    inline void Collection<T>::AddAll (CONTAINER_OF_ADDABLE&& c)
    {
        /*
         * Because adding items to a Collection COULD result in those items appearing in a running iterator,
         * for the corner case of s.AddAll(s) - we want to assure we don't infinite loop.
         */
        if (static_cast<const void*> (this) == static_cast<const void*> (addressof (c))) {
            CONTAINER_OF_ADDABLE tmp = c;
            AddAll (std::begin (tmp), std::end (tmp));
        }
        else {
            AddAll (std::begin (c), std::end (c));
        }
    }
    template <typename T>
    inline void Collection<T>::Add (ArgByValueType<T> item)
    {
        _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (item);
        Ensure (not this->IsEmpty ());
    }
    template <typename T>
    inline void Collection<T>::Update (const Iterator<T>& i, ArgByValueType<T> newValue)
    {
        _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Update (i, newValue);
    }
    template <typename T>
    template <typename EQUALS_COMPARER>
    inline void Collection<T>::Remove (ArgByValueType<T> item, const EQUALS_COMPARER& equalsComparer)
    {
        for (Iterator<T> i = this->begin (); i != this->end (); ++i) {
            if (equalsComparer (*i, item)) {
                _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Remove (i);
                return;
            }
        }
    }
    template <typename T>
    inline void Collection<T>::RemoveAll ()
    {
        _SafeReadWriteRepAccessor<_IRep> tmp{this};
        if (not tmp._ConstGetRep ().IsEmpty ()) {
            tmp._UpdateRep (tmp._ConstGetRep ().CloneEmpty (this));
        }
    }
    template <typename T>
    template <typename COPY_FROM_ITERATOR_OF_ADDABLE, typename EQUALS_COMPARER>
    void Collection<T>::RemoveAll (COPY_FROM_ITERATOR_OF_ADDABLE start, COPY_FROM_ITERATOR_OF_ADDABLE end, const EQUALS_COMPARER& equalsComparer)
    {
        for (auto i = start; i != end; ++i) {
            Remove (*i, equalsComparer);
        }
    }
    template <typename T>
    template <typename CONTAINER_OF_ADDABLE, typename EQUALS_COMPARER>
    inline void Collection<T>::RemoveAll (const CONTAINER_OF_ADDABLE& c, const EQUALS_COMPARER& equalsComparer)
    {
        if (static_cast<const void*> (this) == static_cast<const void*> (addressof (c))) {
            RemoveAll (equalsComparer);
        }
        else {
            RemoveAll (std::begin (c), std::end (c), equalsComparer);
        }
    }
    template <typename T>
    template <typename PREDICATE>
    nonvirtual size_t Collection<T>::RemoveAll (const PREDICATE& p)
    {
        size_t nRemoved{};
        for (Iterator<T> i = this->begin (); i != this->end (); ++i) {
            if (p (*i)) {
                Remove (i);
                nRemoved++;
            }
        }
        return nRemoved;
    }
    template <typename T>
    inline void Collection<T>::Remove (const Iterator<T>& i)
    {
        _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Remove (i);
    }
    template <typename T>
    template <typename PREDICATE>
    nonvirtual bool Collection<T>::Remove (const PREDICATE& p)
    {
        for (Iterator<T> i = this->begin (); i != this->end (); ++i) {
            if (p (*i)) {
                Remove (i);
                return true;
            }
        }
        return false;
    }
    template <typename T>
    inline void Collection<T>::clear ()
    {
        RemoveAll ();
    }
    template <typename T>
    template <typename EQUALS_COMPARER>
    inline void Collection<T>::erase (ArgByValueType<T> item, const EQUALS_COMPARER& equalsComparer)
    {
        Remove (item, equalsComparer);
    }
    template <typename T>
    inline void Collection<T>::erase (const Iterator<T>& i)
    {
        Remove (i);
    }
    template <typename T>
    inline Collection<T> Collection<T>::Where (const function<bool (ArgByValueType<T>)>& doToElement) const
    {
        return Iterable<T>::Where (doToElement, Collection<T>{});
    }
    template <typename T>
    inline Collection<T>& Collection<T>::operator+= (ArgByValueType<T> item)
    {
        Add (item);
        return *this;
    }
    template <typename T>
    inline Collection<T>& Collection<T>::operator+= (const Iterable<T>& items)
    {
        AddAll (items);
        return *this;
    }
    template <typename T>
    inline void Collection<T>::_AssertRepValidType () const
    {
#if qDebug
        _SafeReadRepAccessor<_IRep>{this};
#endif
    }

    /*
     ********************************************************************************
     ********************************* operator+ ************************************
     ********************************************************************************
     */
    template <typename T>
    Collection<T> operator+ (const Iterable<T>& lhs, const Collection<T>& rhs)
    {
        Collection<T> result{lhs};
        result += rhs;
        return result;
    }
    template <typename T>
    Collection<T> operator+ (const Collection<T>& lhs, const Iterable<T>& rhs)
    {
        Collection<T> result{lhs};
        result += rhs;
        return result;
    }
    template <typename T>
    Collection<T> operator+ (const Collection<T>& lhs, const Collection<T>& rhs)
    {
        Collection<T> result{lhs};
        result += rhs;
        return result;
    }

}

#endif /* _Stroika_Foundation_Containers_Collection_inl_ */
<commit_msg>fixed typo<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2020.  All rights reserved
 */
#ifndef _Stroika_Foundation_Containers_Collection_inl_
#define _Stroika_Foundation_Containers_Collection_inl_

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */

#include "../Debug/Assertions.h"

#include "Factory/Collection_Factory.h"

namespace Stroika::Foundation::Containers {

    /*
     ********************************************************************************
     ******************************** Collection<T> *********************************
     ********************************************************************************
     */
    template <typename T>
    inline Collection<T>::Collection ()
        : inherited (Factory::Collection_Factory<T>{}())
    {
        _AssertRepValidType ();
    }
    template <typename T>
    template <typename COPY_FROM_ITERATOR_OF_ADDABLE>
    inline Collection<T>::Collection (COPY_FROM_ITERATOR_OF_ADDABLE start, COPY_FROM_ITERATOR_OF_ADDABLE end)
        : Collection{}
    {
        AddAll (start, end);
        _AssertRepValidType ();
    }
    template <typename T>
    inline Collection<T>::Collection (const _CollectionRepSharedPtr& src) noexcept
        : inherited{src}
    {
        RequireNotNull (src);
        _AssertRepValidType ();
    }
    template <typename T>
    inline Collection<T>::Collection (_CollectionRepSharedPtr&& src) noexcept
        : inherited ((RequireNotNull (src), move (src)))
    {
        _AssertRepValidType ();
    }
    template <typename T>
    inline Collection<T>::Collection (const initializer_list<T>& src)
        : Collection{}
    {
        AddAll (src);
        _AssertRepValidType ();
    }
    template <typename T>
    template <typename CONTAINER_OF_ADDABLE, enable_if_t<Configuration::IsIterableOfT_v<CONTAINER_OF_ADDABLE, T> and not is_base_of_v<Collection<T>, Configuration::remove_cvref_t<CONTAINER_OF_ADDABLE>>>*>
    inline Collection<T>::Collection (CONTAINER_OF_ADDABLE&& src)
        : Collection{}
    {
        AddAll (forward<CONTAINER_OF_ADDABLE> (src));
        _AssertRepValidType ();
    }
#if qDebug
    template <typename T>
    Collection<T>::~Collection ()
    {
        if (this->_GetSharingState () != Memory::SharedByValue_State::eNull) {
            // SharingState can be NULL because of MOVE semantics
            _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().AssertNoIteratorsReferenceOwner (this);
        }
    }
#endif
    template <typename T>
    template <typename EQUALS_COMPARER>
    bool Collection<T>::Contains (ArgByValueType<T> item, const EQUALS_COMPARER& equalsComparer) const
    {
        for (auto&& i : *this) {
            if (equalsComparer (i, item)) {
                return true;
            }
        }
        return false;
    }
    template <typename T>
    template <typename COPY_FROM_ITERATOR_OF_ADDABLE>
    void Collection<T>::AddAll (COPY_FROM_ITERATOR_OF_ADDABLE start, COPY_FROM_ITERATOR_OF_ADDABLE end)
    {
        _SafeReadWriteRepAccessor<_IRep> tmp{this};
        for (auto&& i = start; i != end; ++i) {
            tmp._GetWriteableRep ().Add (*i);
        }
    }
    template <typename T>
    template <typename CONTAINER_OF_ADDABLE, enable_if_t<Configuration::IsIterableOfT_v<CONTAINER_OF_ADDABLE, T>>*>
    inline void Collection<T>::AddAll (CONTAINER_OF_ADDABLE&& c)
    {
        /*
         * Because adding items to a Collection COULD result in those items appearing in a running iterator,
         * for the corner case of s.AddAll(s) - we want to assure we don't infinite loop.
         */
        if (static_cast<const void*> (this) == static_cast<const void*> (addressof (c))) {
            CONTAINER_OF_ADDABLE tmp = c;
            AddAll (std::begin (tmp), std::end (tmp));
        }
        else {
            AddAll (std::begin (c), std::end (c));
        }
    }
    template <typename T>
    inline void Collection<T>::Add (ArgByValueType<T> item)
    {
        _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (item);
        Ensure (not this->IsEmpty ());
    }
    template <typename T>
    inline void Collection<T>::Update (const Iterator<T>& i, ArgByValueType<T> newValue)
    {
        _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Update (i, newValue);
    }
    template <typename T>
    template <typename EQUALS_COMPARER>
    inline void Collection<T>::Remove (ArgByValueType<T> item, const EQUALS_COMPARER& equalsComparer)
    {
        for (Iterator<T> i = this->begin (); i != this->end (); ++i) {
            if (equalsComparer (*i, item)) {
                _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Remove (i);
                return;
            }
        }
    }
    template <typename T>
    inline void Collection<T>::RemoveAll ()
    {
        _SafeReadWriteRepAccessor<_IRep> tmp{this};
        if (not tmp._ConstGetRep ().IsEmpty ()) {
            tmp._UpdateRep (tmp._ConstGetRep ().CloneEmpty (this));
        }
    }
    template <typename T>
    template <typename COPY_FROM_ITERATOR_OF_ADDABLE, typename EQUALS_COMPARER>
    void Collection<T>::RemoveAll (COPY_FROM_ITERATOR_OF_ADDABLE start, COPY_FROM_ITERATOR_OF_ADDABLE end, const EQUALS_COMPARER& equalsComparer)
    {
        for (auto i = start; i != end; ++i) {
            Remove (*i, equalsComparer);
        }
    }
    template <typename T>
    template <typename CONTAINER_OF_ADDABLE, typename EQUALS_COMPARER>
    inline void Collection<T>::RemoveAll (const CONTAINER_OF_ADDABLE& c, const EQUALS_COMPARER& equalsComparer)
    {
        if (static_cast<const void*> (this) == static_cast<const void*> (addressof (c))) {
            RemoveAll (equalsComparer);
        }
        else {
            RemoveAll (std::begin (c), std::end (c), equalsComparer);
        }
    }
    template <typename T>
    template <typename PREDICATE>
    nonvirtual size_t Collection<T>::RemoveAll (const PREDICATE& p)
    {
        size_t nRemoved{};
        for (Iterator<T> i = this->begin (); i != this->end (); ++i) {
            if (p (*i)) {
                Remove (i);
                nRemoved++;
            }
        }
        return nRemoved;
    }
    template <typename T>
    inline void Collection<T>::Remove (const Iterator<T>& i)
    {
        _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Remove (i);
    }
    template <typename T>
    template <typename PREDICATE>
    nonvirtual bool Collection<T>::Remove (const PREDICATE& p)
    {
        for (Iterator<T> i = this->begin (); i != this->end (); ++i) {
            if (p (*i)) {
                Remove (i);
                return true;
            }
        }
        return false;
    }
    template <typename T>
    inline void Collection<T>::clear ()
    {
        RemoveAll ();
    }
    template <typename T>
    template <typename EQUALS_COMPARER>
    inline void Collection<T>::erase (ArgByValueType<T> item, const EQUALS_COMPARER& equalsComparer)
    {
        Remove (item, equalsComparer);
    }
    template <typename T>
    inline void Collection<T>::erase (const Iterator<T>& i)
    {
        Remove (i);
    }
    template <typename T>
    inline Collection<T> Collection<T>::Where (const function<bool (ArgByValueType<T>)>& doToElement) const
    {
        return Iterable<T>::Where (doToElement, Collection<T>{});
    }
    template <typename T>
    inline Collection<T>& Collection<T>::operator+= (ArgByValueType<T> item)
    {
        Add (item);
        return *this;
    }
    template <typename T>
    inline Collection<T>& Collection<T>::operator+= (const Iterable<T>& items)
    {
        AddAll (items);
        return *this;
    }
    template <typename T>
    inline void Collection<T>::_AssertRepValidType () const
    {
#if qDebug
        _SafeReadRepAccessor<_IRep>{this};
#endif
    }

    /*
     ********************************************************************************
     ********************************* operator+ ************************************
     ********************************************************************************
     */
    template <typename T>
    Collection<T> operator+ (const Iterable<T>& lhs, const Collection<T>& rhs)
    {
        Collection<T> result{lhs};
        result += rhs;
        return result;
    }
    template <typename T>
    Collection<T> operator+ (const Collection<T>& lhs, const Iterable<T>& rhs)
    {
        Collection<T> result{lhs};
        result += rhs;
        return result;
    }
    template <typename T>
    Collection<T> operator+ (const Collection<T>& lhs, const Collection<T>& rhs)
    {
        Collection<T> result{lhs};
        result += rhs;
        return result;
    }

}

#endif /* _Stroika_Foundation_Containers_Collection_inl_ */
<|endoftext|>