diff --git a/demo/bit.cpp b/demo/bit.cpp deleted file mode 100644 index 956caea..0000000 --- a/demo/bit.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "../include/tools" - -signed main() { - [[maybe_unused]] - Bit <1> a; // Create a 1-bit object, default to 0 - - Bit <10> b(10); // Create a 10-bit object - - auto ref = b.slice <4, 2> (); // A copy of [2, 3, 4] bit - - std::cout << b << std::endl; // 10 - - b.set <3, 1> (ref); // Set [1, 2, 3] bit to [2, 3, 4] bit - - std::cout << b << std::endl; // 4 - - b.set <0> (~a); // Set the 0-th bit to ~a (= 1 in this case) - - std::cout << b << std::endl; // 5 - - auto sec = b.slice <2> (); // A copy of the 2-th bit (= 1 in this case) - - auto d = sec.zero_extend(); // Zero extend (default to 32-bit) - - std::cout << d << std::endl; // 1 - - auto c = sec.sign_extend <3> (); // Sign extend (default to 32-bit) - - std::cout << c << std::endl; // 7 - - // c + d; // Error: different size - // a += 1; // Error: no assignment-operation operator - - auto e = b - 1; // normal integer can be assumed as any size - - std::cout << e << std::endl; // 4 - - return 0; -} diff --git a/demo/hardware.cpp b/demo/hardware.cpp deleted file mode 100644 index a7d09ae..0000000 --- a/demo/hardware.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "../include/tools" - -struct Input { - Wire a; - Wire b; - std::array c; -}; - -struct Output { - Register d; - Register e; -}; - -struct Content { - Register r; -}; - -struct MyModule : Input, Output, private Content { - using Tags = SyncTags ; - friend class Visitor; - - void demo() { this->d <= this->a + this->b; } -}; - -signed main() { - MyModule m; - - m.a = []() { return 1; }; - m.b.assign([&]() { return (target_size_t)m.d; }); - - for (int i = 0 ; i < 10 ; ++i) { - std::cout << m.d << std::endl; - m.demo(); - std::cout << m.d << std::endl; - sync_member(m); - } - return 0; -} diff --git a/include/bit.h b/include/bit.h index e71e9be..992ecbb 100644 --- a/include/bit.h +++ b/include/bit.h @@ -1,20 +1,13 @@ #pragma once -#include "target.h" +#include "concept.h" #include "debug.h" #include +#include #include -namespace dark::bits { +namespace dark { -static constexpr std::size_t kMaxLength = 8 * sizeof(target_size_t); - -template -constexpr auto int_concat(target_size_t arg) { return arg; } - -template -constexpr auto int_concat(target_size_t arg, auto ...args) { - return (arg << (_Lens + ...)) | int_concat<_Lens...>(args...); -} +static constexpr std::size_t kMaxLength = std::numeric_limits::digits; template struct Bit { @@ -22,117 +15,38 @@ struct Bit { static_assert(0 < _Nm && _Nm <= kMaxLength, "Bit: _Nm out of range. Should be in [1, kMaxLength]"); - target_size_t _M_data : _Nm; // Real storage + max_size_t _M_data : _Nm; // Real storage + + template + static constexpr void _M_range_check(); public: static constexpr std::size_t _Bit_Len = _Nm; - constexpr Bit(target_size_t data = {}) : _M_data(data) {} + constexpr Bit(max_size_t data = 0) : _M_data(data) {} - template - constexpr Bit(Bit<_Lens> ...args) requires ((_Lens + ...) == _Nm) : - _M_data(int_concat<_Lens...>(args...)) {} + constexpr explicit operator max_size_t() const { return this->_M_data; } - constexpr Bit(const Bit &val) = default; + template + requires ((_Tp::_Bit_Len + ...) == _Nm) + constexpr Bit(const _Tp &...args); - template - constexpr Bit(const Bit <_Len> &val) requires (_Len != _Nm) { - static_assert(_Len == _Nm, "Bit: bit length mismatch"); - } + template _Tp> + constexpr Bit &operator=(const _Tp &val); - constexpr Bit &operator=(const Bit &val) = default; - - template requires (_Len != _Nm) - constexpr Bit &operator=(const Bit <_Len> &val) { - static_assert(_Len == _Nm, "Bit: bit length mismatch"); - return *this; - } - - constexpr Bit &operator=(target_size_t val) { - this->_M_data = val; - return *this; - } - - constexpr operator target_size_t() const { return this->_M_data; } + template _Tp> + constexpr void set(const _Tp &val); template - constexpr auto set(Bit <_Hi - _Lo + 1> val) { - static_cast (this->slice<_Hi, _Lo>()); - const auto mask = // Mask those bit in the middle - (target_size_t(1) << (_Hi + 1)) - (target_size_t(1) << _Lo); - const auto data = // Set those bit in the middle - static_cast (val) << _Lo; - this->_M_data = (this->_M_data & ~mask) | data; - } - - template - constexpr auto slice() const -> Bit <_Hi - _Lo + 1> { - static_assert(_Lo <= _Hi, "Bit::slice: _Lo should be no greater than _Hi"); - static_assert(_Hi < _Nm, "Bit::slice: _Hi should be less than _Nm"); - return Bit<_Hi - _Lo + 1>(this->_M_data >> _Lo); - } + constexpr auto range() const -> Bit <_Hi - _Lo + 1>; template - constexpr auto at(target_size_t pos) const -> Bit <_Len> { - static_assert(_Len != 0, "Bit::at: _Len should be greater than 0"); - debug::assert(pos + _Len <= _Nm, "Bit::at: pos out of range"); - return Bit <_Len> (this->_M_data >> pos); - } + constexpr auto slice(std::size_t pos) const -> Bit <_Len>; - constexpr auto operator [](target_size_t pos) const -> Bit <1> { return this->at(pos); } - - template - constexpr auto zero_extend() const -> Bit<_New>; - - template - constexpr auto sign_extend() const -> Bit<_New>; + constexpr Bit <1> operator [](std::size_t pos) const { return this->slice(pos); } }; -template -static constexpr bool is_bit_v = false; -template -static constexpr bool is_bit_v> = true; - -template -concept BitType = is_bit_v<_Tp>; - -template +template Bit(_Tp...) -> Bit<(_Tp::_Bit_Len + ...)>; -template -constexpr auto sign_extend(target_size_t val) { - static_assert(_Old < _New, "sign_extend: _Old should be less than _New"); - struct { target_ssize_t _M_data : _Old; } tmp; - return Bit<_New>(tmp._M_data = val); -} - -template -constexpr auto sign_extend(_Tp val) { - return sign_extend<_Tp::_Bit_Len, _New>(static_cast(val)); -} - -template -constexpr auto zero_extend(target_size_t val) { - static_assert(_Old < _New, "zero_extend: _Old should be less than _New"); - struct { target_size_t _M_data : _Old; } tmp; - return Bit<_New>(tmp._M_data = val); -} - -template -constexpr auto zero_extend(_Tp val) { - return zero_extend<_Tp::_Bit_Len, _New>(static_cast(val)); -} - -template -template -constexpr auto Bit<_Nm>::sign_extend() const -> Bit<_New> { - return ::dark::bits::sign_extend<_New> (*this); -} - -template -template -constexpr auto Bit<_Nm>::zero_extend() const -> Bit<_New> { - return ::dark::bits::zero_extend<_New> (*this); -} - -} // namespace dark::bits +} // namespace dark diff --git a/include/bit_impl.h b/include/bit_impl.h new file mode 100644 index 0000000..a62f15d --- /dev/null +++ b/include/bit_impl.h @@ -0,0 +1,94 @@ +#pragma once +#include "bit.h" + +namespace dark { + +template +constexpr auto int_concat(max_size_t arg) { return arg; } + +template +constexpr auto int_concat(max_size_t arg, auto ...args) { + return (arg << (_Lens + ...)) | int_concat<_Lens...>(args...); +} + +template +constexpr auto sign_extend(max_size_t val) { + static_assert(_Old < _New, "sign_extend: _Old should be less than _New"); + struct { max_ssize_t _M_data : _Old; } tmp; + return Bit<_New>(tmp._M_data = val); +} + +template +constexpr auto sign_extend(const _Tp & val) { + return sign_extend<_Tp::_Bit_Len, _New>(static_cast(val)); +} + +template +constexpr auto zero_extend(max_size_t val) { + static_assert(_Old < _New, "zero_extend: _Old should be less than _New"); + struct { max_size_t _M_data : _Old; } tmp; + return Bit<_New>(tmp._M_data = val); +} + +template +constexpr auto zero_extend(const _Tp &val) { + return zero_extend<_Tp::_Bit_Len, _New>(static_cast(val)); +} + +template +template +requires ((_Tp::_Bit_Len + ...) == _Nm) +constexpr Bit<_Nm>::Bit(const _Tp &...args) + : _M_data(int_concat<_Tp::_Bit_Len...>(static_cast(args)...)) {} + +template +template > _Tp> +constexpr Bit<_Nm> &Bit<_Nm>::operator=(const _Tp &val) { + this->_M_data = static_cast(val); + return *this; +} + +template +template +constexpr void Bit<_Nm>::_M_range_check() { + static_assert(_Lo <= _Hi, "Bit::range_check: _Lo should be no greater than _Hi"); + static_assert(_Hi < _Nm, "Bit::range_check: _Hi should be less than _Nm"); +} + +template +template > _Tp> +constexpr void Bit<_Nm>::set(const _Tp &val) { + this->_M_range_check<_Hi, _Lo>(); + auto data = static_cast(val); + constexpr auto _Length = _Hi - _Lo + 1; + if constexpr (_Length == kMaxLength) { + this->_M_data = data; + } else { + auto mask = ((1 << _Length) - 1) << _Lo; + this->_M_data = (this->_M_data & ~mask) | ((data << _Lo) & mask); + } +} + +template +template +constexpr auto Bit<_Nm>::range() const -> Bit <_Hi - _Lo + 1> { + this->_M_range_check<_Hi, _Lo>(); + constexpr auto _Length = _Hi - _Lo + 1; + return Bit<_Length>(this->_M_data >> _Lo); +} + +template +template +constexpr auto Bit<_Nm>::slice(std::size_t pos) const -> Bit <_Len> { + static_assert(_Len <= _Nm, "Bit::slice: _Len should be no greater than _Nm"); + debug::assert(pos <= _Nm - _Len, "Bit::slice: pos should be less than _Nm - _Len"); + if constexpr (_Len == kMaxLength) { + return *this; + } else { + return Bit<_Len>(this->_M_data >> pos); + } +} + + + +} // namespace dark diff --git a/include/bit_op.h b/include/bit_op.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/include/bit_op.h @@ -0,0 +1 @@ +#pragma once diff --git a/include/bitop.h b/include/bitop.h deleted file mode 100644 index 27d5db3..0000000 --- a/include/bitop.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include "bit.h" - -namespace dark::bits { - -template -concept NonBit = !BitType<_Tp>; - -template -auto cast(_Tp &&val) -> target_size_t { - return static_cast(val); -} - -template -constexpr auto operator + (_Lhs lhs, _Rhs rhs) { - static_assert(_Lhs::_Bit_Len == _Rhs::_Bit_Len, - "operator +: lhs and rhs should have the same length"); - return _Lhs { cast(lhs) + cast(rhs) }; -} - -template -constexpr auto operator + (_Lhs lhs, _Rhs &&rhs) { - return _Lhs { cast(lhs) + cast(rhs) }; -} - -template -constexpr auto operator + (_Lhs &&lhs, _Rhs rhs) { - return _Rhs { cast(lhs) + cast(rhs) }; -} - - -} // namespace dark::bits diff --git a/include/concept.h b/include/concept.h new file mode 100644 index 0000000..6d47846 --- /dev/null +++ b/include/concept.h @@ -0,0 +1,41 @@ +#pragma once +#include +#include + +namespace dark { + +using max_size_t = std::uint32_t; +using max_ssize_t = std::int32_t; + +} // namespace dark + +namespace dark::concepts { + +template +using func_t = void(*)(_Tp); + +template +concept implicit_convertible_to = requires(_From &a, func_t <_To> b) { + b(a); // Can implicitly convert +}; + +template +concept explicit_convertible_to = + !implicit_convertible_to <_From, _To> +&& std::constructible_from <_To, _From>; + +template +concept has_length = requires { _Tp::_Bit_Len; }; + +template +concept bit_type = has_length <_Tp> && explicit_convertible_to <_Tp, max_size_t>; + +template +concept int_type = !has_length <_Tp> && implicit_convertible_to <_Tp, max_size_t>; + +template +concept bit_match = + (bit_type <_Lhs> && bit_type <_Rhs> && _Lhs::_Bit_Len == _Rhs::_Bit_Len) +|| (int_type <_Lhs> || int_type <_Rhs>); + +} // namespace dark::concepts diff --git a/include/hardware.h b/include/hardware.h index 1ab1c32..e10a48b 100644 --- a/include/hardware.h +++ b/include/hardware.h @@ -1,7 +1,8 @@ #pragma once #include "debug.h" -#include "target.h" +#include "concept.h" #include +#include #include namespace dark::hardware { @@ -13,7 +14,7 @@ struct Register; template concept WireFunction = !std::same_as > && - requires(_Fn &&__f) { { __f() } -> std::convertible_to ; }; + requires(_Fn &&__f) { { __f() } -> std::convertible_to ; }; struct WireBase { using _Ret_t = int; @@ -46,7 +47,7 @@ struct Wire { using _Manage_t = WireBase; std::unique_ptr <_Manage_t> _M_impl; - mutable target_size_t _M_cache; + mutable max_size_t _M_cache; mutable bool _M_holds; [[no_unique_address]] @@ -65,7 +66,6 @@ struct Wire { } public: - Wire() : _M_impl(new EmptyWire), _M_cache(), _M_holds(), _M_dirty() {} Wire(Wire &&) = delete; @@ -90,7 +90,7 @@ struct Wire { this->_M_holds = false; } - operator target_size_t() const { + operator max_size_t() const { if (this->_M_holds == false) { this->_M_cache = this->_M_impl->call(); this->_M_holds = true; @@ -103,8 +103,8 @@ struct Register { private: friend struct Visitor; - target_size_t _M_new; - target_size_t _M_old; + max_size_t _M_new; + max_size_t _M_old; [[no_unique_address]] debug::DebugValue _M_dirty; @@ -116,15 +116,16 @@ struct Register { } } - void set_value(target_size_t value) { + void set_value(max_size_t value) { this->_M_new = value; debug::assert(!this->_M_dirty, "Register is already assigned in this cycle."); this->_M_dirty = true; } - auto get_value() const -> target_size_t { return this->_M_old; } + auto get_value() const -> max_size_t { return this->_M_old; } public: + Register() : _M_new(), _M_old(), _M_dirty() {} Register(Register &&) = delete; @@ -132,12 +133,12 @@ struct Register { Register &operator=(Register &&) = delete; Register &operator=(const Register &rhs) = delete; - template _Int> + template _Int> void operator <= (_Int &&value) { - this->set_value(static_cast (value)); + this->set_value(static_cast (value)); } - operator target_size_t() const { return this->get_value(); } + operator max_size_t() const { return this->get_value(); } }; } // namespace dark::hardware diff --git a/include/target.h b/include/target.h deleted file mode 100644 index 8daf92c..0000000 --- a/include/target.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include - -namespace dark { - -using target_size_t = std::uint32_t; -using target_ssize_t = std::int32_t; - -} // namespace dark diff --git a/include/tools b/include/tools deleted file mode 100644 index b0817d9..0000000 --- a/include/tools +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "target.h" -#include "hardware.h" -#include "synchronize.h" -#include "bit.h" -#include "bitop.h" - -using ::dark::target_size_t; -using ::dark::target_ssize_t; - -using ::dark::hardware::Register; -using ::dark::hardware::Wire; -using ::dark::hardware::Visitor; -using ::dark::hardware::SyncTags; -using ::dark::hardware::sync_member; - -using ::dark::bits::Bit;