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
6 changes: 3 additions & 3 deletions include/groov/write.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ auto write(Spec const &s) -> async::sender auto {
all_fields_per_reg_t,
written_fields_per_reg_t>;

using field_masks_t = boost::mp11::mp_transform<detail::compute_mask_t,
typename Spec::value_t,
written_fields_per_reg_t>;
using field_masks_t =
boost::mp11::mp_transform<detail::compute_mask_t,
typename Spec::value_t, fields_per_reg_t>;

detail::check_read_only<typename Spec::bus_t, fields_per_reg_t>();
detail::check_rmw<typename Spec::bus_t, unwritten_fields_per_reg_t,
Expand Down
4 changes: 2 additions & 2 deletions test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,14 @@ TEST_CASE("test_bus write function", "[test]") {
write_value = get<std::uint32_t>(value).value_or(0);
});

groov::sync_write(grp0("reg0"_r = 0x76));
groov::sync_write(grp0("reg0"_r = 0x10325476u));

CHECK(data0 == 0xa5a5'a5a5u);
CHECK(my_bus::num_reads == 0);
CHECK(my_bus::num_writes == 0);
CHECK(write_call_count == 1);
CHECK(write_addr == &data0);
CHECK(write_value == 0xbabefa76u);
CHECK(write_value == 0x10325476u);
auto v = groov::test::get_value<G0>("reg0"_f);
REQUIRE(v);
CHECK(*v == 0xbabefaceu);
Expand Down
72 changes: 72 additions & 0 deletions test/write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include <array>
#include <cstdint>
#include <limits>

namespace {
struct bus {
Expand Down Expand Up @@ -549,3 +550,74 @@ TEST_CASE("write a field in a register containing WO fields which won't be "
CHECK(groov::write(grp_be("reg4.field0"_r = 1)) | async::sync_wait());
CHECK(data3 == 42);
}

namespace {
struct rmw_check_bus {
static inline std::uint32_t expected_mask{};

template <stdx::ct_string, auto Mask, auto IdMask, auto IdValue>
static auto write(auto addr, auto value) -> async::sender auto {
CHECK((Mask | IdMask) == expected_mask);
return async::just_result_of([=] {
auto prev = *addr & ~(Mask | IdMask);
*addr = prev | value | IdValue;
});
}

template <stdx::ct_string, auto Mask>
static auto read(auto addr) -> async::sender auto {
return async::just_result_of([=] { return *addr; });
}
};

std::uint32_t rmw_check_data{};
using rmw_check_R = groov::reg<"r", std::uint32_t, &rmw_check_data,
groov::w::replace, F0, F1, F2>;

using rmw_check_G = groov::group<"group", rmw_check_bus, rmw_check_R>;
constexpr auto rmw_check_grp = rmw_check_G{};
} // namespace

TEST_CASE("writing a register that is not covered by fields does not RMW",
"[write]") {
using namespace groov::literals;
rmw_check_bus::expected_mask = 0xffff'ffffu;
rmw_check_data = 0;
CHECK(groov::write(rmw_check_grp("r"_r = 0xa5a5u)) | async::sync_wait());
CHECK(rmw_check_data == 0xa5a5u);
}

TEST_CASE("writing register fields in a register that is not covered by fields "
"incurs RMW",
"[write]") {
using namespace groov::literals;
rmw_check_bus::expected_mask = 0xffu;
rmw_check_data = 0;
CHECK(
groov::write(rmw_check_grp("r.field0"_f = 0b1u, "r.field1"_f = 0b1010u,
"r.field2"_f = 0b110u)) |
async::sync_wait());
CHECK(rmw_check_data == 0b110'1010'1u);
}

namespace {
using F_overlap = groov::field<"f_overlap", std::uint8_t, 3, 0>;

std::uint32_t overlap_data{};
using R_overlap = groov::reg<"r", std::uint32_t, &overlap_data,
groov::w::replace, F0, F_overlap>;

using G_overlap = groov::group<"group", bus, R_overlap>;
constexpr auto overlap_grp = G_overlap{};
} // namespace

TEST_CASE("overlapping writes: last one takes priority", "[write]") {
using namespace groov::literals;
overlap_data = 0xffff'ffffu;
CHECK(sync_write(overlap_grp("r.f_overlap"_r = 0, "r.field0"_f = 1)));
CHECK(overlap_data == 0xffff'fff1u);

overlap_data = 0xffff'ffffu;
CHECK(sync_write(overlap_grp("r.field0"_f = 1, "r.f_overlap"_r = 0)));
CHECK(overlap_data == 0xffff'fff0u);
}