feat(wire & register): implement these 2 components

This commit is contained in:
DarkSharpness
2024-07-11 21:53:52 +08:00
parent 7ebe48fe09
commit 72b0c5bcf0
5 changed files with 167 additions and 146 deletions

View File

@ -1,6 +1,8 @@
#pragma once #pragma once
#include <utility> #include <utility>
#ifdef _DEBUG
#include <iostream> #include <iostream>
#endif
#include <source_location> #include <source_location>
namespace dark::debug { namespace dark::debug {

View File

@ -1,144 +0,0 @@
#pragma once
#include "debug.h"
#include "concept.h"
#include <memory>
#include <cstdint>
#include <concepts>
namespace dark::hardware {
struct Visitor;
struct Wire;
struct Register;
template <typename _Fn>
concept WireFunction =
!std::same_as <Wire, std::decay_t <_Fn>> &&
requires(_Fn &&__f) { { __f() } -> std::convertible_to <max_size_t>; };
struct WireBase {
using _Ret_t = int;
using _Cpy_t = WireBase *;
virtual _Ret_t call() const = 0;
virtual ~WireBase() = default;
};
template <WireFunction _Fn>
struct WireImpl final : WireBase {
_Fn _M_lambda;
template <typename _Fn2>
WireImpl(_Fn2 &&fn) : _M_lambda(std::forward <_Fn2>(fn)) {}
_Ret_t call() const override { return this->_M_lambda(); }
};
struct EmptyWire final : WireBase {
_Ret_t call() const override {
debug::assert(false, "Empty wire is called.");
debug::unreachable();
}
};
struct Wire {
private:
friend struct Visitor;
using _Manage_t = WireBase;
std::unique_ptr <_Manage_t> _M_impl;
mutable max_size_t _M_cache;
mutable bool _M_holds;
[[no_unique_address]]
debug::DebugValue <bool, false> _M_dirty; // Can be assigned only once
void sync() { this->_M_holds = false; }
template <WireFunction _Fn>
static auto _M_new_impl(_Fn &&fn) -> _Manage_t * {
return new WireImpl <std::decay_t<_Fn>> {std::forward <_Fn>(fn)};
}
void _M_check_double_assign() {
debug::assert(!this->_M_dirty, "Wire is already assigned.");
this->_M_dirty = true;
}
public:
Wire() : _M_impl(new EmptyWire), _M_cache(), _M_holds(), _M_dirty() {}
Wire(Wire &&) = delete;
Wire(const Wire &) = delete;
Wire &operator=(Wire &&) = delete;
Wire &operator=(const Wire &rhs) = delete;
template <WireFunction _Fn>
Wire(_Fn &&fn)
: _M_impl(_M_new_impl(std::forward <_Fn>(fn))), _M_cache(), _M_holds(), _M_dirty() {}
template <WireFunction _Fn>
Wire &operator=(_Fn &&fn) {
this->assign(std::forward <_Fn>(fn));
return *this;
}
template <WireFunction _Fn>
void assign(_Fn &&fn) {
this->_M_check_double_assign();
this->_M_impl.reset(this->_M_new_impl(std::forward <_Fn>(fn)));
this->_M_holds = false;
}
operator max_size_t() const {
if (this->_M_holds == false) {
this->_M_cache = this->_M_impl->call();
this->_M_holds = true;
}
return this->_M_cache;
}
};
struct Register {
private:
friend struct Visitor;
max_size_t _M_new;
max_size_t _M_old;
[[no_unique_address]]
debug::DebugValue <bool, false> _M_dirty;
void sync() {
if (this->_M_dirty) {
this->_M_old = this->_M_new;
this->_M_dirty = false;
}
}
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 -> max_size_t { return this->_M_old; }
public:
Register() : _M_new(), _M_old(), _M_dirty() {}
Register(Register &&) = delete;
Register(const Register &) = delete;
Register &operator=(Register &&) = delete;
Register &operator=(const Register &rhs) = delete;
template <std::convertible_to <max_size_t> _Int>
void operator <= (_Int &&value) {
this->set_value(static_cast <max_size_t>(value));
}
operator max_size_t() const { return this->get_value(); }
};
} // namespace dark::hardware

48
include/register.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include "debug.h"
#include "concept.h"
namespace dark {
template <std::size_t _Len>
struct Register {
private:
static_assert(0 < _Len && _Len <= kMaxLength,
"Register: _Len must be in range [1, kMaxLength].");
friend class Visitor;
max_size_t _M_old : _Len;
max_size_t _M_new : _Len;
[[no_unique_address]]
debug::DebugValue <bool, false> _M_assigned;
void sync() {
if (this->_M_assigned) {
this->_M_assigned = false;
this->_M_old = this->_M_new;
}
}
public:
static constexpr bool _Bit_Len = _Len;
explicit Register() : _M_old(), _M_new(), _M_assigned() {}
Register(Register &&) = delete;
Register(const Register &) = delete;
Register &operator=(Register &&) = delete;
Register &operator=(const Register &rhs) = delete;
template <concepts::bit_convertible <_Len> _Tp>
void operator <= (_Tp &&value) {
debug::assert(!this->_M_assigned, "Register is double assigned in this cycle.");
this->_M_assigned = true;
this->_M_new = static_cast <max_size_t> (value);
}
explicit operator max_size_t() const { return this->_M_old; }
};
} // namespace dark

View File

@ -1,9 +1,8 @@
#pragma once #pragma once
#include "hardware.h"
#include "reflect.h" #include "reflect.h"
#include <array> #include <array>
namespace dark::hardware { namespace dark {
struct Visitor { struct Visitor {
template <typename _Tp> template <typename _Tp>

116
include/wire.h Normal file
View File

@ -0,0 +1,116 @@
#pragma once
#include "debug.h"
#include "concept.h"
#include <memory>
namespace dark {
namespace details {
template <typename _Fn, std::size_t _Len>
concept WireFunction = requires(_Fn &&func) {
{ func() } -> concepts::bit_convertible <_Len>;
};
struct FuncBase {
using _Ret_t = int;
using _Cpy_t = FuncBase *;
virtual _Ret_t call() const = 0;
virtual _Cpy_t copy() const = 0;
virtual ~FuncBase() = default;
};
template <std::size_t _Len, WireFunction <_Len> _Fn>
struct FuncImpl final : FuncBase {
_Fn _M_lambda;
template <typename _Tp>
FuncImpl(_Tp &&fn) : _M_lambda(std::forward <_Tp> (fn)) {}
_Ret_t call() const override { return this->_M_lambda(); }
_Cpy_t copy() const override { return new FuncImpl(*this); }
};
struct EmptyWire final : FuncBase {
_Ret_t call() const override {
debug::assert(false, "Empty wire is called.");
debug::unreachable();
}
_Cpy_t copy() const override { return new EmptyWire; }
};
} // namespace details
template <std::size_t _Len>
struct Wire {
private:
static_assert(0 < _Len && _Len <= kMaxLength,
"Wire: _Len must be in range [1, kMaxLength].");
friend class Visitor;
using _Manage_t = std::unique_ptr <details::FuncBase>;
_Manage_t _M_func;
mutable max_size_t _M_cache;
mutable bool _M_holds;
[[no_unique_address]]
debug::DebugValue <bool, false> _M_assigned;
void sync() { this->_M_holds = false; }
template <details::WireFunction <_Len> _Fn>
static auto _M_new_func(_Fn &&fn) {
using _Decay_t = std::decay_t <_Fn>;
return new details::FuncImpl <_Len, _Decay_t> {std::forward <_Fn>(fn)};
}
void _M_checked_assign() {
debug::assert(!this->_M_assigned, "Wire is assigned twice.");
this->_M_assigned = true;
}
public:
static constexpr bool _Bit_Len = _Len;
explicit Wire() :
_M_func(new details::EmptyWire),
_M_cache(), _M_holds(), _M_assigned() {}
explicit operator max_size_t() const {
if (this->_M_holds == false) {
this->_M_holds = true;
constexpr auto mask = make_mask <_Len> ();
this->_M_cache = this->_M_func->call() & mask;
}
return this->_M_cache;
}
Wire(Wire &&) = delete;
Wire(const Wire &) = delete;
Wire &operator=(Wire &&) = delete;
Wire &operator=(const Wire &rhs) = delete;
template <details::WireFunction <_Len> _Fn>
Wire(_Fn &&fn) :
_M_func(_M_new_func(std::forward <_Fn> (fn))),
_M_cache(), _M_holds(), _M_assigned() {}
template <details::WireFunction <_Len> _Fn>
Wire &operator=(_Fn &&fn) {
return this->assign(std::forward <_Fn> (fn)), *this;
}
template <details::WireFunction <_Len> _Fn>
void assign(_Fn &&fn) {
this->_M_checked_assign();
this->_M_func.reset(_M_new_func(std::forward <_Fn> (fn)));
this->sync();
}
};
} // namespace dark