microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
register.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Jarosław Pelczar <jarek@jpelczar.com>
2//
3// SPDX-License-Identifier: BSD-2-Clause
4
5#pragma once
6
10#include "../microfmt.hpp"
11#include <cstddef>
12#include <cstdint>
13#include <string_view>
14#include <type_traits>
15
16namespace microfmt {
17
18// ============================================================================
19// Static Bitfield / Register Descriptors (Placed in Flash / .rodata)
20// ============================================================================
21
25struct MICROFMT_API_CLASS RELOCO_POINTER reg_field {
29 microfmt::string_view name;
33 uint8_t bit_offset{};
37 uint8_t bit_width{};
41 bool is_flag{false}; // If true (width=1), format as +FLAG / -FLAG or flag name only
42};
43
51template <size_t N> struct RELOCO_POINTER reg_descriptor {
55 microfmt::string_view name;
59 size_t byte_width{4}; // 1, 2, 4, or 8 bytes
63 reg_field fields[N];
64};
65
69template <typename... Fields>
70reg_descriptor(microfmt::string_view, size_t, Fields...) -> reg_descriptor<sizeof...(Fields)>;
71
72// ============================================================================
73// Register Value + Descriptor View
74// ============================================================================
75
81template <size_t N, typename UInt = uint32_t> struct RELOCO_POINTER reg_view {
85 UInt value;
89 const reg_descriptor<N> *desc{nullptr};
90};
91
100template <size_t N, typename UInt>
101[[nodiscard]] constexpr auto format_reg(UInt val, const reg_descriptor<N> &desc) noexcept {
102 return reg_view<N, UInt>{val, &desc};
103}
104
105// ============================================================================
106// Formatter for Register View
107// ============================================================================
108
118template <size_t N, typename UInt> struct formatter<reg_view<N, UInt>> {
122 bool detailed{true}; // 'd' -> detailed fields, 's' -> short (active flags only)
126 bool naked{false}; // 'n' -> no outer braces
127
132 constexpr void parse(format_parse_context &ctx) noexcept {
133 auto spec = ctx.spec();
134 for (char c : spec) {
135 if (c == 's' || c == 'S')
136 detailed = false;
137 else if (c == 'n' || c == 'N')
138 naked = true;
139 }
140 }
141
147 void format(const reg_view<N, UInt> &rv, const sink &out) const noexcept {
148 if (!rv.desc)
149 return;
150 const auto &d = *rv.desc;
151
152 // Register Name & Raw Value
153 out.write(d.name);
154 out.write("=0x");
155 detail::format_unsigned<detail::radix::hex>(out, static_cast<uint64_t>(rv.value), true,
156 static_cast<int>(d.byte_width * 2));
157
158 // Decode Bitfields
159 if (!naked)
160 out.write(" [");
161 else
162 out.put(' ');
163
164 size_t printed_count = 0;
165 for (size_t i = 0; i < N; ++i) {
166 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE
167
168 const auto &f = d.fields[i];
169
170 RELOCO_END_UNSAFE_BUFFER_USAGE
171
172 const uint64_t mask = (f.bit_width == 64) ? ~0ULL : ((1ULL << f.bit_width) - 1ULL);
173 const uint64_t val = (static_cast<uint64_t>(rv.value) >> f.bit_offset) & mask;
174
175 if (f.is_flag || f.bit_width == 1) {
176 if (!detailed && val == 0) {
177 continue; // Short mode: skip inactive flags
178 }
179 if (printed_count++ > 0)
180 out.write(", ");
181
182 if (val != 0) {
183 out.write(f.name);
184 } else {
185 out.put('!');
186 out.write(f.name);
187 }
188 } else {
189 if (!detailed && val == 0) {
190 continue; // Short mode: skip zeroed fields
191 }
192 if (printed_count++ > 0)
193 out.write(", ");
194
195 out.write(f.name);
196 out.put('=');
197 if (val > 9) {
198 out.write("0x");
199 detail::format_unsigned<detail::radix::hex>(out, val, false, 0);
200 } else {
201 detail::format_unsigned<detail::radix::decimal>(out, val, false, 0);
202 }
203 }
204 }
205
206 if (!naked)
207 out.put(']');
208 }
209};
210
211} // namespace microfmt
Definition microfmt.hpp:881
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Definition assert.hpp:19
constexpr auto format_reg(UInt val, const reg_descriptor< N > &desc) noexcept
Builds a reg_view from a register value and its descriptor.
Definition register.hpp:101
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
constexpr void parse(format_parse_context &ctx) noexcept
Parses the s/S and n/N mode flags.
Definition register.hpp:132
void format(const reg_view< N, UInt > &rv, const sink &out) const noexcept
Renders the register name, raw value, and decoded bitfields.
Definition register.hpp:147
Definition microfmt.hpp:985
Static register descriptor listing its bitfields.
Definition register.hpp:51
microfmt::string_view name
Register name.
Definition register.hpp:55
Describes a single bitfield within a register.
Definition register.hpp:25
microfmt::string_view name
Human-readable field name.
Definition register.hpp:29
Non-owning view pairing a register value with its static descriptor.
Definition register.hpp:81
UInt value
Raw register value.
Definition register.hpp:85