mbv: debugging the async app

This commit is contained in:
2025-06-27 12:58:43 -07:00
parent e4936abb53
commit e7b38fb560
8 changed files with 339 additions and 33 deletions

View File

@@ -63,9 +63,6 @@ async::task<> echo() {
} // namespace
#define XUL_SR_RX_FIFO_FULL 0x02 /* receive FIFO full */
#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */
int main() {
SetupUart();
UartWriteCrash("uart setup done\r\n");
@@ -99,10 +96,6 @@ int main() {
#include "itoa.h"
#include "lock.h"
#ifndef SBRK_STATS
#define SBRK_STATS 0
#endif
extern unsigned char _heap_begin, _heap_end;
extern "C" void* _sbrk(int increment) {

108
mbv/apps/async/main2.cc Normal file
View File

@@ -0,0 +1,108 @@
#include "buffer.h"
#include "gpio.h"
#include "intc.h"
#include "interrupts.h"
#include "pol0.h"
#include "timer.h"
#include "trace.h"
#include "uart2.h"
namespace {
Timer* timer0;
void Uart0Isr() {
// ToggleLed(7);
HandleUartIsr();
}
void Timer0Isr() {
SetLed(6);
__builtin_trap();
}
void SetupUart() {
InitUarts();
intc::SetIsr(UART0_IRQN, Uart0Isr);
intc::SetIrqEnabled(UART0_IRQN, true);
}
void SetupTimer() {
timer0 = Timer::Instance(TIMER0_BASE);
// timer0->SetupAsWdt(100'000 * 1000);
timer0->EnableT1();
intc::SetIsr(TIMER0_IRQN, Timer0Isr);
intc::SetIrqEnabled(TIMER0_IRQN, true);
}
void SetupInterrupts() {
intc::EnableInterrupts();
SetExternalInterruptHandler(intc::InterruptHandler);
EnableExternalInterrupts();
EnableInterrupts(true);
}
} // namespace
int main() {
SetupUart();
UartWriteCrash("uart setup done\r\n");
SetupTimer();
UartWriteCrash("timer setup done\r\n");
SetupInterrupts();
UartWriteCrash("init done. starting main loop\r\n");
UartEcho();
// should never get here
}
/// stdlib stuff
#include <sys/time.h>
#include <cstdint>
#include "itoa.h"
#include "lock.h"
extern unsigned char _heap_begin, _heap_end;
extern "C" void* _sbrk(int increment) {
static unsigned char* heap = &_heap_begin;
unsigned char* prev_heap = heap;
if (heap + increment >= &_heap_end) {
UartWriteCrash("Heap overflow!\r\n");
return reinterpret_cast<void*>(-1);
}
heap += increment;
return prev_heap;
}
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;
return 0;
}
extern "C" uint8_t __atomic_exchange_1(volatile void* ptr, uint8_t val,
int memorder) {
(void)memorder;
auto* dest = reinterpret_cast<volatile uint8_t*>(ptr);
bool ret;
{
InterruptLock lock;
ret = *dest;
*dest = val;
}
return ret;
}

View File

@@ -1,6 +1,5 @@
#pragma once
#include <atomic>
#include <span>
#include "lock.h"
@@ -8,9 +7,9 @@
struct RingBuffer {
std::span<std::byte> buffer;
std::atomic<size_t> read_ptr = 0;
std::atomic<size_t> write_ptr = 0;
std::atomic<bool> full = 0;
size_t read_ptr = 0;
size_t write_ptr = 0;
size_t used = 0;
bool Store(std::span<const std::byte> data) {
InterruptLock lock;
@@ -53,9 +52,7 @@ struct RingBuffer {
return false;
}
write_ptr = (write_ptr + amount) % buffer.size();
if (read_ptr == write_ptr) {
full = true;
}
used = used + amount;
return true;
}
@@ -66,25 +63,20 @@ struct RingBuffer {
return false;
}
read_ptr = (read_ptr + amount) % buffer.size();
if (amount > 0) {
full = false;
}
used = used - amount;
return true;
}
size_t FreeSpace() const {
InterruptLock lock;
return buffer.size() - AvailableData();
return buffer.size() - used;
}
size_t AvailableData() const {
InterruptLock lock;
if (read_ptr == write_ptr) {
return full ? buffer.size() : 0;
}
return (buffer.size() + write_ptr - read_ptr) % buffer.size();
return used;
}
uint8_t* RawReadPointer() const {
@@ -93,16 +85,21 @@ struct RingBuffer {
return reinterpret_cast<uint8_t*>(buffer.data() + read_ptr);
}
uint8_t* RawWritePointer() const {
InterruptLock lock;
return reinterpret_cast<uint8_t*>(buffer.data() + write_ptr);
}
size_t ContiguousFreeSpace() const {
InterruptLock lock;
return std::min(FreeSpace(), buffer.size() - write_ptr);
}
size_t ContiguousAvailableData() const {
InterruptLock lock;
if (read_ptr < write_ptr) {
return AvailableData();
}
if (full) {
return 0;
}
return buffer.size() - read_ptr;
return std::min(AvailableData(), buffer.size() - read_ptr);
}
};

View File

@@ -27,6 +27,8 @@ std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
XUartLite* uart0 = &uart0_inst;
bool sending;
} // namespace
void InitUarts() {
@@ -35,9 +37,12 @@ void InitUarts() {
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
XUartLite_EnableInterrupt(uart0);
sending = false;
}
void UartWriteCrash(std::span<const std::byte> data) {
XUartLite_DisableInterrupt(uart0);
while (data.size() > 0) {
while (XUartLite_IsSending(uart0)) {
}
@@ -48,6 +53,7 @@ void UartWriteCrash(std::span<const std::byte> data) {
}
while (XUartLite_IsSending(uart0)) {
}
XUartLite_EnableInterrupt(uart0);
}
async::task<> UartWrite(std::span<const std::byte> data) {
@@ -79,10 +85,11 @@ async::task<> UartWriteLoop(
{
InterruptLock lock;
if (!XUartLite_IsSending(uart0)) {
if (!sending) {
tracing::trace(tracing::TraceEvent::kUartSend);
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData());
sending = true;
}
}
}
@@ -139,11 +146,13 @@ async::task<buffer> UartRead(int size) {
}
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
sending = false;
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());
sending = true;
}
async::resume(AwaitableType::kUartTx);
}

119
mbv/apps/async/uart2.cc Normal file
View File

@@ -0,0 +1,119 @@
#include "uart2.h"
#include "gpio.h"
#include "lock.h"
#include "pol0.h"
#include "ring_buffer.h"
#include "xuartlite.h"
namespace {
constexpr uintptr_t kUart0BaseAddress = UART0_BASE;
XUartLite uart0_inst;
XUartLite_Config uart0_config = {
.DeviceId = 0,
.RegBaseAddr = kUart0BaseAddress,
.BaudRate = 115200,
.UseParity = false,
.DataBits = 8,
};
constexpr size_t kUartRxBufferSize = 256;
std::array<std::byte, kUartRxBufferSize> rx_buffer = {};
RingBuffer rx_ring_buffer{.buffer = rx_buffer};
constexpr size_t kUartTxBufferSize = 256;
std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
XUartLite* uart0 = &uart0_inst;
volatile int sending = 0;
void StartReceiving() {
while (1) {
if (rx_ring_buffer.FreeSpace() < 1) {
// woops, full. discard some data
// TODO: keep track of overrun stats
rx_ring_buffer.Pop(1);
}
if (XUartLite_Recv(uart0, rx_ring_buffer.RawWritePointer(), 1) < 1) {
break;
}
rx_ring_buffer.Push(1);
}
}
void StartSending() {
if (tx_ring_buffer.AvailableData() > 0 && sending < 1) {
sending += 1;
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), 1);
}
}
std::byte UartReadByte() {
std::byte c;
while (!rx_ring_buffer.Load(std::span{&c, 1})) {
}
return c;
}
void UartWriteByte(std::byte c) {
while (!tx_ring_buffer.Store(std::span{&c, 1})) {
}
{
InterruptLock lock;
StartSending();
}
}
} // namespace
void InitUarts() {
XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr);
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
StartReceiving();
XUartLite_EnableInterrupt(uart0);
}
void UartWriteCrash(std::span<const std::byte> data) {
XUartLite_DisableInterrupt(uart0);
while (data.size() > 0) {
while (XUartLite_IsSending(uart0)) {
}
auto* dat =
reinterpret_cast<uint8_t*>(const_cast<std::byte*>(data.data()));
uint8_t sent = XUartLite_Send(uart0, dat, data.size());
data = data.subspan(sent);
}
while (XUartLite_IsSending(uart0)) {
}
XUartLite_EnableInterrupt(uart0);
}
void UartEcho() {
while (1) {
gpio0->data = tx_ring_buffer.AvailableData();
std::byte c = UartReadByte();
UartWriteByte(c);
//gpio0->data = uart0->Stats.ReceiveOverrunErrors;
}
}
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
sending -= 1;
tx_ring_buffer.Pop(transmitted);
StartSending();
}
void HandleUartRxFromIsr(void*, unsigned int transmitted) {
rx_ring_buffer.Push(transmitted);
StartReceiving();
}
void HandleUartIsr() { XUartLite_InterruptHandler(uart0); }

18
mbv/apps/async/uart2.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include <span>
#include <string_view>
void InitUarts();
// send and poll the uart until transmitted
void UartWriteCrash(std::span<const std::byte> data);
inline void UartWriteCrash(std::string_view s) {
return UartWriteCrash(std::as_bytes(std::span{s.data(), s.size()}));
}
void UartEcho();
void HandleUartTxFromIsr(void*, unsigned int transmitted);
void HandleUartRxFromIsr(void*, unsigned int);
void HandleUartIsr();