microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
pl011_sink.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
9#include "../microfmt.hpp"
10#include "../reloco.hpp"
11#include <cstdint>
12
13namespace microfmt {
14
22public:
28 explicit constexpr pl011_sink(uintptr_t base_addr, bool translate_crlf = true) noexcept
29 : base_(base_addr), translate_crlf_(translate_crlf) {}
30
34 void enable() const noexcept {
35 volatile uint32_t *cr = reinterpret_cast<volatile uint32_t *>(base_ + 0x30);
36 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
37 // Bit 0: UARTEN (Enabled), Bit 8: TXE (Transmit Enable), Bit 9: RXE (Receive Enable)
38 *cr |= (1 << 0) | (1 << 8) | (1 << 9);
39 RELOCO_END_UNSAFE_BUFFER_USAGE;
40 }
41
45 [[nodiscard]] constexpr sink as_sink() const noexcept {
46 return sink{const_cast<void *>(static_cast<const void *>(this)), &pl011_sink::write_impl};
47 }
48
49private:
50 uintptr_t base_;
51 bool translate_crlf_;
52
53 static void write_impl(void *ctx, string_view str) noexcept {
54 auto *self = static_cast<pl011_sink *>(ctx);
55
56 volatile uint32_t *dr = reinterpret_cast<volatile uint32_t *>(self->base_);
57 volatile uint32_t *fr = reinterpret_cast<volatile uint32_t *>(self->base_ + 0x18); // Flag Register
58
59 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
60 for (char c : str) {
61 if (self->translate_crlf_ && c == '\n') {
62 wait_for_fifo_slot(fr);
63 *dr = static_cast<uint32_t>('\r');
64 }
65
66 wait_for_fifo_slot(fr);
67 *dr = static_cast<uint32_t>(c);
68 }
69 RELOCO_END_UNSAFE_BUFFER_USAGE;
70 }
71
72 static inline void wait_for_fifo_slot(volatile uint32_t *fr_reg) noexcept {
73 // Loop while TXFF (Transmit FIFO Full, bit 5) is set
74 while ((*fr_reg & (1 << 5)) != 0) {
75#if defined(__aarch64__) || defined(__arm__)
76 __asm__ volatile("yield" ::: "memory");
77#endif
78 }
79 }
80};
81
82} // namespace microfmt
Zero-allocation controller targeting the ARM PrimeCell PL011 UART.
Definition pl011_sink.hpp:21
constexpr pl011_sink(uintptr_t base_addr, bool translate_crlf=true) noexcept
Constructs a PL011 UART controller.
Definition pl011_sink.hpp:28
void enable() const noexcept
Optional hardware initialization helper.
Definition pl011_sink.hpp:34
constexpr sink as_sink() const noexcept
Returns a type-erased microfmt::sink view over this controller instance.
Definition pl011_sink.hpp:45
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Definition assert.hpp:19
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46