From dd51b5d61047f49ede107931aa817ef51e38f470 Mon Sep 17 00:00:00 2001 From: Paul Mathieu Date: Mon, 21 Jul 2025 10:06:12 +0200 Subject: [PATCH] mbv: async debugging in progres... --- mbv/apps/async/async.cc | 4 -- mbv/apps/async/async.h | 109 ++++++++++++++-------------------------- mbv/apps/async/main.cc | 39 ++++++++++---- mbv/apps/async/main2.cc | 4 +- mbv/apps/async/uart.cc | 3 +- mbv/apps/async/uart2.cc | 3 +- mbv/hal/timer.h | 4 ++ 7 files changed, 78 insertions(+), 88 deletions(-) diff --git a/mbv/apps/async/async.cc b/mbv/apps/async/async.cc index 9bc5056..8310bcf 100644 --- a/mbv/apps/async/async.cc +++ b/mbv/apps/async/async.cc @@ -84,10 +84,6 @@ void step() { stuff->h(); TRACE(tracing::TraceEvent::kAsyncTaskDone); - if (stuff->h.done()) { - stuff->h.destroy(); - } // XXX: else?? - { InterruptLock lock; work = stuff->next; diff --git a/mbv/apps/async/async.h b/mbv/apps/async/async.h index 975c45d..88a5537 100644 --- a/mbv/apps/async/async.h +++ b/mbv/apps/async/async.h @@ -8,22 +8,12 @@ namespace async { -struct task_final_suspend { - bool await_ready() noexcept(true) { return false; } - void await_suspend(std::coroutine_handle<> h) noexcept(true) { +struct continuation : std::suspend_always { + void await_suspend(std::coroutine_handle<>) noexcept { if (parent) { - TRACE(tracing::TraceEvent::kAsyncCallParent); - parent(); - TRACE(tracing::TraceEvent::kAsyncCallParentDone); - - if (parent && parent.done()) { - TRACE(tracing::TraceEvent::kAsyncDestroy); - parent.destroy(); - } + parent.resume(); } } - void await_resume() noexcept(true) {} - std::coroutine_handle<> parent; }; @@ -35,40 +25,37 @@ struct task { struct promise_type; using handle_type = std::coroutine_handle; + ~task() { + if (h) { + h.destroy(); + } + } + struct promise_type { task get_return_object() { return {.h = handle_type::from_promise(*this)}; } std::suspend_always initial_suspend() noexcept { return {}; } - task_final_suspend final_suspend() noexcept { - return {.parent = parent}; - } + continuation final_suspend() noexcept { return {.parent = parent}; } void return_void() {} - void unhandled_exception() { - TRACE(tracing::TraceEvent::kAsyncException); - } + void unhandled_exception() {} std::coroutine_handle<> parent; }; // awaitable bool await_ready() { - TRACE(tracing::TraceEvent::kAsyncCoAwait); - h(); + h.promise().parent = {}; + h.resume(); if (h.done()) { - TRACE(tracing::TraceEvent::kAsyncDestroy); - h.destroy(); return true; } return false; } - void await_suspend(std::coroutine_handle<> ha) { - TRACE(tracing::TraceEvent::kAsyncSuspend); - h.promise().parent = ha; - } + void await_suspend(std::coroutine_handle<> ha) { h.promise().parent = ha; } void await_resume() {} - std::coroutine_handle h; + handle_type h; }; template @@ -76,20 +63,22 @@ struct task { struct promise_type; using handle_type = std::coroutine_handle; + ~task() { + if (h) { + h.destroy(); + } + } + struct promise_type { task get_return_object() { return {.h = handle_type::from_promise(*this)}; } std::suspend_always initial_suspend() noexcept { return {}; } - task_final_suspend final_suspend() noexcept { - return {.parent = parent}; - } + continuation final_suspend() noexcept { return {.parent = parent}; } void return_value(T&& value) { ret_value = std::move(value); } - void unhandled_exception() { - TRACE(tracing::TraceEvent::kAsyncException); - } + void unhandled_exception() {} template From> - task_final_suspend yield_value(From&& value) { + continuation yield_value(From&& value) { ret_value = std::forward(value); result_ready = true; return {.parent = parent}; @@ -103,34 +92,18 @@ struct task { // awaitable bool await_ready() { h.promise().parent = {}; - TRACE(tracing::TraceEvent::kAsyncCoAwait); - h(); - if (h.promise().result_ready) { - return true; - } - if (h.done()) { - destroyed = true; - ret_value = std::move(h.promise().ret_value); - TRACE(tracing::TraceEvent::kAsyncDestroy); - h.destroy(); + h.resume(); + if (h.promise().result_ready || h.done()) { return true; } return false; } - void await_suspend(std::coroutine_handle<> ha) { - TRACE(tracing::TraceEvent::kAsyncSuspend); - h.promise().parent = ha; - } + void await_suspend(std::coroutine_handle<> ha) { h.promise().parent = ha; } T await_resume() { - if (!destroyed) { - h.promise().result_ready = false; - return std::move(h.promise().ret_value); - } - return std::move(ret_value); + h.promise().result_ready = false; + return std::move(h.promise().ret_value); } - bool destroyed = false; - T ret_value; std::coroutine_handle h; }; @@ -181,12 +154,11 @@ struct gimme { ha = h; waiting = true; TRACE(tracing::TraceEvent::kAsyncGimmeWaiting); - if (suspended) { + if (parent) { schedule(parent); } } T await_resume() { - suspended = false; waiting = false; TRACE(tracing::TraceEvent::kAsyncGimmeResume); return std::move(stuff); @@ -196,18 +168,14 @@ struct gimme { auto feed(T&& s) { struct awaitable { bool await_ready() { - g->ha.resume(); - if (!g->waiting) { - g->suspended = true; - } - return !g->suspended; + g.parent = {}; + g.ha.resume(); + return g.waiting; } - void await_suspend(std::coroutine_handle<> h) { - g->parent = h; - } - void await_resume() { } + void await_suspend(std::coroutine_handle<> h) { g.parent = h; } + void await_resume() {} - gimme* g; + gimme& g; }; if (!waiting) { @@ -216,11 +184,10 @@ struct gimme { if (!ha) { __builtin_trap(); } - stuff = s; - return awaitable{.g = this}; + stuff = std::move(s); + return awaitable{.g = *this}; } - bool suspended = false; bool waiting = false; std::coroutine_handle<> ha; std::coroutine_handle<> parent; diff --git a/mbv/apps/async/main.cc b/mbv/apps/async/main.cc index 5397d40..8249766 100644 --- a/mbv/apps/async/main.cc +++ b/mbv/apps/async/main.cc @@ -11,14 +11,28 @@ namespace { -Timer* timer0; +constexpr uint32_t kTicksPerSecond = 100'000'000; +constexpr uint32_t kTicksPerMicrosecond = 100; +constexpr uint32_t kOverflowSeconds = (1ULL << 32) / kTicksPerSecond; +constexpr uint32_t kOverflowMicroseconds = + ((1ULL << 32) % kTicksPerSecond) / kTicksPerMicrosecond; -void Uart0Isr() { - HandleUartIsr(); -} +Timer* timer0; +volatile uint32_t t1overflowsecs = 0; +volatile uint32_t t1overflowusecs = 0; + +void Uart0Isr() { HandleUartIsr(); } void Timer0Isr() { + if (timer0->HasT1Overflowed()) { + UartWriteCrash("t1 overflow\r\n"); + t1overflowsecs += kOverflowSeconds; + t1overflowusecs += kOverflowMicroseconds; + timer0->ClearT1Overflow(); + return; + } SetLed(6); + UartWriteCrash("blarg\r\n"); __builtin_trap(); } @@ -63,6 +77,8 @@ async::task<> blink() { co_await async::delay(500); ToggleLed(0); timer0->Pet(); + + co_await UartWrite("."); } } @@ -77,12 +93,16 @@ int main() { gpio0->data = 0; SetupInterrupts(); - async::schedule(echo().h); - async::schedule(blink().h); + auto e = echo(); + auto b = blink(); + async::schedule(e.h); + async::schedule(b.h); UartWriteBlocking("init done. starting main loop\r\n"); - async::main_loop(nullptr); + async::main_loop([]() { + return false; + }); // should never get here } @@ -111,8 +131,9 @@ extern "C" void* _sbrk(int increment) { extern "C" int _gettimeofday(struct timeval* tv, void* tzvp) { (void)tzvp; uint32_t ticks = timer0->GetT1Ticks(); - tv->tv_sec = ticks / 100000000; - tv->tv_usec = (ticks % 100000000) / 100; + tv->tv_sec = ticks / kTicksPerSecond + t1overflowsecs; + tv->tv_usec = + (ticks % kTicksPerSecond) / kTicksPerMicrosecond + t1overflowusecs; return 0; } diff --git a/mbv/apps/async/main2.cc b/mbv/apps/async/main2.cc index 73a2828..eb59a9e 100644 --- a/mbv/apps/async/main2.cc +++ b/mbv/apps/async/main2.cc @@ -12,7 +12,7 @@ namespace { Timer* timer0; void Uart0Isr() { -// ToggleLed(7); + // ToggleLed(7); HandleUartIsr(); } @@ -30,7 +30,7 @@ void SetupUart() { void SetupTimer() { timer0 = Timer::Instance(TIMER0_BASE); -// timer0->SetupAsWdt(100'000 * 1000); + // timer0->SetupAsWdt(100'000 * 1000); timer0->EnableT1(); intc::SetIsr(TIMER0_IRQN, Timer0Isr); diff --git a/mbv/apps/async/uart.cc b/mbv/apps/async/uart.cc index e3168db..de3cd99 100644 --- a/mbv/apps/async/uart.cc +++ b/mbv/apps/async/uart.cc @@ -84,7 +84,8 @@ void UartWriteCrash(std::span data) { } while (XUartLite_IsSending(uart0)) { } - XUartLite_Send(uart0, nullptr, 0); // reset buffer before enabling interrupts + XUartLite_Send(uart0, nullptr, + 0); // reset buffer before enabling interrupts XUartLite_EnableInterrupt(uart0); } diff --git a/mbv/apps/async/uart2.cc b/mbv/apps/async/uart2.cc index f00bb60..2a551cf 100644 --- a/mbv/apps/async/uart2.cc +++ b/mbv/apps/async/uart2.cc @@ -96,7 +96,8 @@ void UartWriteCrash(std::span data) { } while (XUartLite_IsSending(uart0)) { } - XUartLite_Send(uart0, nullptr, 0); // reset buffer before enabling interrupts + XUartLite_Send(uart0, nullptr, + 0); // reset buffer before enabling interrupts XUartLite_EnableInterrupt(uart0); } diff --git a/mbv/hal/timer.h b/mbv/hal/timer.h index 9ec246b..6cb8d7d 100644 --- a/mbv/hal/timer.h +++ b/mbv/hal/timer.h @@ -37,11 +37,15 @@ struct Timer { void EnableT1() { TCSR1.ARHT0 = 1; + TCSR1.ENIT0 = 1; // enable interrupt for overflows TCSR1.ENT0 = 1; } uint32_t GetT1Ticks() { return TCR1; } + bool HasT1Overflowed() { return TCSR1.T0INT; } + void ClearT1Overflow() { TCSR1.T0INT = 1; } + void SetupAsWdt(uint32_t timeout_ticks) { TLR0 = timeout_ticks; TCSR0.LOAD0 = 1; // reset counter