11constexpr uintptr_t Data = 0x000;
12constexpr uintptr_t Flags = 0x018;
13constexpr uintptr_t IntegerBaud = 0x024;
14constexpr uintptr_t FractionalBaud = 0x028;
15constexpr uintptr_t LineControl = 0x02c;
16constexpr uintptr_t Control = 0x030;
17constexpr uintptr_t InterruptMask = 0x038;
18constexpr uintptr_t InterruptClear = 0x044;
19constexpr uint32_t TxFull = 1U << 5;
20constexpr uint32_t RxEmpty = 1U << 4;
21constexpr size_t PollLimit = 100000;
23volatile uint32_t& registerAt(uintptr_t base, uintptr_t offset) {
24 return *
reinterpret_cast<volatile uint32_t*
>(base + offset);
28VirtSerial::VirtSerial() : m_Base(0) {}
36 registerAt(base, Control) = 0;
37 registerAt(base, InterruptMask) = 0;
38 registerAt(base, InterruptClear) = 0x7ff;
40 registerAt(base, IntegerBaud) = 13;
41 registerAt(base, FractionalBaud) = 1;
42 registerAt(base, LineControl) = (3U << 5) | (1U << 4);
43 registerAt(base, Control) = (1U << 9) | (1U << 8) | 1U;
50 if (!(registerAt(base, Control) & 1U)) {
51 registerAt(base, Control) = 0;
52 registerAt(base, InterruptMask) = 0;
53 registerAt(base, IntegerBaud) = 13;
54 registerAt(base, FractionalBaud) = 1;
55 registerAt(base, LineControl) = (3U << 5) | (1U << 4);
56 registerAt(base, Control) = (1U << 9) | (1U << 8) | 1U;
58 for (
size_t i = 0; i < PollLimit; ++i) {
59 if (!(registerAt(base, Flags) & TxFull)) {
60 registerAt(base, Data) =
static_cast<uint8_t
>(c);
63 asm volatile(
"yield");
67bool VirtSerial::hasData() {
68 return m_Base && !(registerAt(m_Base, Flags) & RxEmpty);
71char VirtSerial::read() {
76 asm volatile(
"yield");
78 return static_cast<char>(registerAt(m_Base, Data));
81char VirtSerial::readNonBlock() {
82 return hasData() ?
static_cast<char>(registerAt(m_Base, Data)) : 0;
85void VirtSerial::write(
char c) {
void setBase(uintptr_t base) override
static void earlyWrite(uintptr_t base, char c)