From 9ae472afafdac147923813e926207871fbb9881f Mon Sep 17 00:00:00 2001 From: Paul Mathieu Date: Sun, 19 Jun 2022 09:45:04 +0200 Subject: [PATCH] arm: more uart async & debug stuff --- arm/async.h | 58 +++++++++++++++++++++++++++++++++ arm/uart.cc | 83 ++++++++++++++++++++++++++++++++++++++++++------ arm/uart.h | 4 +++ arm/uart_async.h | 2 ++ 4 files changed, 138 insertions(+), 9 deletions(-) diff --git a/arm/async.h b/arm/async.h index 7acc00d..589380e 100644 --- a/arm/async.h +++ b/arm/async.h @@ -30,6 +30,64 @@ struct task_final_suspend { std::coroutine_handle<> parent; }; +template +struct gimme { + // child interface + bool await_ready() { return false; } + void await_suspend(std::coroutine_handle<> h) { + ha = h; + waiting = true; + TRACE(tracing::TraceEvent::kAsyncGimmeWaiting); + + if (parent) { + TRACE(tracing::TraceEvent::kAsyncCallParent); + parent.resume(); + TRACE(tracing::TraceEvent::kAsyncCallParentDone); + } + } + T await_resume() { + waiting = false; + TRACE(tracing::TraceEvent::kAsyncGimmeResume); + return std::move(stuff); + } + + // parent interface + auto feed(T&& s) { + struct awaitable { + bool await_ready() { + if (g.waiting) { + return true; + } + // TODO: handle g.ha.done() + return false; + } + void await_suspend(std::coroutine_handle<> h) { + g.parent = h; + } + void await_resume() {} + + gimme& g; + }; + + if (!waiting) { + __builtin_trap(); + } + if (!ha) { + __builtin_trap(); + } + stuff = s; + parent = {}; + ha.resume(); + + return awaitable{.g = *this}; + } + + bool waiting = false; + std::coroutine_handle<> ha; + T stuff; + std::coroutine_handle<> parent; +}; + template struct task; diff --git a/arm/uart.cc b/arm/uart.cc index 123e75f..df7c3cf 100644 --- a/arm/uart.cc +++ b/arm/uart.cc @@ -1,10 +1,11 @@ #include "uart.h" -#include "uart_async.h" #include "async.h" #include "gpio.h" +#include "lock.h" #include "ring_buffer.h" #include "trace.h" +#include "uart_async.h" #include "xuartlite.h" namespace { @@ -54,38 +55,93 @@ void UartWriteCrash(std::span data) { async::task<> UartWrite(std::span data) { while (!tx_ring_buffer.Store(data)) { + tracing::trace(tracing::TraceEvent::kUartTxBufferFull); co_await async::await(AwaitableType::kUartTx); + tracing::trace(tracing::TraceEvent::kUartTxBufferNotFull); } - if (!XUartLite_IsSending(uart0)) { - XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), - tx_ring_buffer.ContiguousAvailableData()); + { + InterruptLock lock; + if (!XUartLite_IsSending(uart0)) { + tracing::trace(tracing::TraceEvent::kUartSend); + XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), + tx_ring_buffer.ContiguousAvailableData()); + } } } +#define GCC_HAS_BUG_101133 1 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101133 +#if !GCC_HAS_BUG_101133 +async::task<> UartWriteLoop(async::gimme>& data_gen) { + while (1) { + auto data = co_await data_gen; + while (!tx_ring_buffer.Store(data)) { + tracing::trace(tracing::TraceEvent::kUartTxBufferFull); + co_await async::await(AwaitableType::kUartTx); + tracing::trace(tracing::TraceEvent::kUartTxBufferNotFull); + } + + { + InterruptLock lock; + if (!XUartLite_IsSending(uart0)) { + tracing::trace(tracing::TraceEvent::kUartSend); + XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), + tx_ring_buffer.ContiguousAvailableData()); + } + } + } +} +#endif // !GCC_HAS_BUG_101133 + void UartReadBlocking(std::span data) { size_t bytes_received = 0; while (bytes_received < data.size()) { auto* buffer = reinterpret_cast(data.data() + bytes_received); + tracing::trace(tracing::TraceEvent::kUartRecv); bytes_received += XUartLite_Recv(uart0, buffer, data.size() - bytes_received); } } void UartWriteBlocking(std::span data) { + if (__get_PRIMASK() != 0) { + UartWriteCrash("\r\nUartWriteBlocking called with interupts disabled!\r\n"); + __builtin_trap(); + } + while (!tx_ring_buffer.Store(data)) { } - if (!XUartLite_IsSending(uart0)) { - XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), - tx_ring_buffer.ContiguousAvailableData()); + { + InterruptLock lock; + if (!XUartLite_IsSending(uart0)) { + tracing::trace(tracing::TraceEvent::kUartSend); + XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), + tx_ring_buffer.ContiguousAvailableData()); + } + } +} + +async::task UartReadLoop() { + uint8_t c; + while (1) { + tracing::trace(tracing::TraceEvent::kUartRecv); + size_t received = XUartLite_Recv(uart0, &c, 1); + // some data may already be in the fifo, but if not, wait: + if (received < 1) { + co_await async::await(AwaitableType::kUartRx); + } + + co_yield c; } } async::task UartRead(int size) { auto buff = buffer::make(size); auto* data = reinterpret_cast(buff.data.data()); + tracing::trace(tracing::TraceEvent::kUartRecv); size_t received = XUartLite_Recv(uart0, data, buff.data.size()); + // some data may already be in the fifo, but if not, wait: if (received < buff.data.size()) { co_await async::await(AwaitableType::kUartRx); } @@ -93,9 +149,9 @@ async::task UartRead(int size) { } void HandleUartTxFromIsr(void*, unsigned int transmitted) { - tracing::trace(tracing::TraceEvent::kUartTxCb); tx_ring_buffer.Pop(transmitted); if (tx_ring_buffer.AvailableData() > 0) { + tracing::trace(tracing::TraceEvent::kUartSend); XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), tx_ring_buffer.ContiguousAvailableData()); } @@ -103,8 +159,17 @@ void HandleUartTxFromIsr(void*, unsigned int transmitted) { } void HandleUartRxFromIsr(void*, unsigned int) { - tracing::trace(tracing::TraceEvent::kUartRxCb); async::resume(AwaitableType::kUartRx); } void HandleUartIsr() { XUartLite_InterruptHandler(uart0); } + +extern "C" uint8_t XUartLite_GetSR(XUartLite*); + +uint8_t UartStatus() { return XUartLite_GetSR(uart0); } + +void LogStuff() { + uint8_t data = gpio0->data; + data |= (uart0->ReceiveBuffer.RemainingBytes & 0xf) << 4; + gpio0->data = data; +} diff --git a/arm/uart.h b/arm/uart.h index affd6ed..ea2c93a 100644 --- a/arm/uart.h +++ b/arm/uart.h @@ -28,3 +28,7 @@ inline void UartWriteBlocking(std::string_view s) { void HandleUartTxFromIsr(void*, unsigned int transmitted); void HandleUartRxFromIsr(void*, unsigned int); void HandleUartIsr(); + +uint8_t UartStatus(); + +void LogStuff(); diff --git a/arm/uart_async.h b/arm/uart_async.h index 44d0937..e6912aa 100644 --- a/arm/uart_async.h +++ b/arm/uart_async.h @@ -7,7 +7,9 @@ #include "buffer.h" async::task UartRead(int size); +async::task UartReadLoop(); async::task<> UartWrite(std::span data); inline async::task<> UartWrite(std::string_view s) { co_await UartWrite(std::as_bytes(std::span{s.data(), s.size()})); } +async::task<> UartWriteLoop(async::gimme>& data);