Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions docs/read_write.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ auto w_spec = grp / ("reg"_r = 42);
assert(w_spec == 42); // implicit conversion
----

=== Read
=== Reading

==== `read`

The `read` function takes a `read_spec` and produces a
https://intel.github.io/cpp-baremetal-senders-and-receivers/[sender].
Expand All @@ -77,6 +79,22 @@ Read can also be piped in a chain of senders.
auto r = async::just(grp / "reg"_r) | groov::read() | async::sync_wait();
----

==== `read_as`

The `read_as` function behaves like `read`, except that it takes a template
(type) argument: the read value will be converted to this type before being
sent. This works when reading one value only.

[source,cpp]
----
auto r = groov::read_as<bool>(grp / "reg"_r);
----

Here, the type of `"reg"_r` must be
https://cppreference.com/cpp/concepts/convertible_to[`convertible_to`] `bool`.

==== `sync_read`

To do a simple read from a bus that is synchronous (e.g. an MMIO bus),
`sync_read` may be called:

Expand All @@ -88,7 +106,9 @@ auto r = async::just(grp / "reg"_r) | groov::sync_read();
NOTE: `sync_read` automatically assumes that the operation will succeed and
returns the resulting `write_spec`.

=== Write
=== Writing

==== `write`

The `write` function takes a `write_spec` and produces a
https://intel.github.io/cpp-baremetal-senders-and-receivers/[sender].
Expand All @@ -111,6 +131,8 @@ Write can also be piped in a chain of senders.
auto r = async::just(grp("reg"_r = 42)) | groov::write() | async::sync_wait();
----

==== `sync_write`

To do a simple write to a bus that is synchronous (e.g. an MMIO bus),
`sync_write` may be called:

Expand Down
2 changes: 2 additions & 0 deletions docs/synopsis.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ No identifiers: this is an omnibus header that includes other headers.

==== https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read.hpp[read.hpp]
* `read` - a function that takes a `read_spec` and produces a sender that produces a `write_spec`
* `read_as<T>` - a function template that takes a `read_spec` and produces a sender that produces a `T`
* `sync_read` - a function that takes a `read_spec` and blocks, producing the `write_spec`

==== https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read_spec.hpp[read_spec.hpp]
Expand Down Expand Up @@ -195,6 +196,7 @@ No public identifiers: this header contains metaprogramming helpers.
* `mmio_bus` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/mmio_bus.hpp[`#include <groov/mmio_bus.hpp>`]
* `path` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/path.hpp[`#include <groov/path.hpp>`]
* `read` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read.hpp[`#include <groov/read.hpp>`]
* `read_as` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read.hpp[`#include <groov/read.hpp>`]
* `read_only` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/identity.hpp[`#include <groov/identity.hpp>`]
* `read_spec` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read_spec.hpp[`#include <groov/read_spec.hpp>`]
* `register` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/config.hpp[`#include <groov/config.hpp>`]
Expand Down
15 changes: 11 additions & 4 deletions include/groov/read.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ template <typename T, typename Spec> consteval auto check_read_conversion() {
}
} // namespace detail

template <typename T = void, typename Group, typename Paths>
constexpr auto read(read_spec<Group, Paths> const &s) -> async::sender auto {
template <typename T, typename Group, typename Paths>
constexpr auto read_as(read_spec<Group, Paths> const &s) -> async::sender auto {
using Spec = decltype(to_write_spec(s));

using fields_per_reg_t = boost::mp11::mp_transform_q<
Expand Down Expand Up @@ -140,16 +140,23 @@ template <typename T> struct pipeable {
friend constexpr auto operator|(S &&s, pipeable) -> async::sender auto {
return std::forward<S>(s) |
async::let_value([]<typename Spec>(Spec &&spec) {
return read<T>(std::forward<Spec>(spec));
return read_as<T>(std::forward<Spec>(spec));
});
}
};
} // namespace _read

template <typename T = void> constexpr auto read() {
template <typename T> constexpr auto read_as() {
return async::compose(_read::pipeable<T>{});
}

template <typename Group, typename Paths>
constexpr auto read(read_spec<Group, Paths> const &s) -> decltype(auto) {
return read_as<void>(s);
}

constexpr inline auto read() { return async::compose(_read::pipeable<void>{}); }

namespace _sync_read {
template <typename Behavior, async::sender S> [[nodiscard]] auto wait(S &&s) {
static_assert(async::trivially_sync_waitable<S> or
Expand Down
2 changes: 1 addition & 1 deletion test/fail/read/read_multi_conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ using G = groov::group<"group", read_bus, R>;

auto main() -> int {
using namespace groov::literals;
[[maybe_unused]] auto x = read<int>(G{}("reg.f0"_f, "reg.f1"_f));
[[maybe_unused]] auto x = read_as<int>(G{}("reg.f0"_f, "reg.f1"_f));
}
12 changes: 10 additions & 2 deletions test/read.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,22 @@ TEST_CASE("read a register", "[read]") {
CHECK(r["reg0"_r] == data0);
}

TEST_CASE("read a register and convert", "[read]") {
TEST_CASE("read a register and convert to its type", "[read]") {
using namespace groov::literals;
data0 = 0xa5a5'a5a5u;
auto s = read<std::uint32_t>(grp / "reg0"_r);
auto s = read_as<std::uint32_t>(grp / "reg0"_r);
auto r = get<0>(*(s | async::sync_wait()));
CHECK(r == data0);
}

TEST_CASE("read a register and convert to different type", "[read]") {
using namespace groov::literals;
data0 = 0xa5a5'a5a5u;
auto s = read_as<bool>(grp / "reg0"_r);
auto r = get<0>(*(s | async::sync_wait()));
CHECK(r);
}

TEST_CASE("sync_read a register", "[read]") {
using namespace groov::literals;
data0 = 0xa5a5'a5a5u;
Expand Down