synth/mbv/apps/async/main.cc

176 lines
3.8 KiB
C++

#include "hal/gpio.h"
#include "hal/intc.h"
#include "hal/interrupts.h"
#include "hal/pol0.h"
#include "hal/timer.h"
#include "lib/async.h"
#include "lib/buffer.h"
#include "uart.h"
#include "uart_async.h"
namespace {
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;
Timer* timer0;
volatile uint32_t t1overflowsecs = 0;
volatile uint32_t t1overflowusecs = 0;
Gpio* gpio0;
void ToggleLed(int which) {
uint8_t data = gpio0->data;
data ^= (0x1 << which);
gpio0->data = data;
}
void SetLed(int which) {
uint8_t data = gpio0->data;
data |= (0x1 << which);
gpio0->data = data;
}
void ClearLed(int which) {
uint8_t data = gpio0->data;
data &= ~(0x1 << which);
gpio0->data = data;
}
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();
}
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);
}
async::task<> echo() {
async::task<std::byte> reader = UartReadLoop();
async::gimme<std::span<const std::byte>> feeder;
async::task<> writer = UartWriteLoop(feeder);
writer.h.resume(); // advance to first yield
while (1) {
SetLed(1);
std::byte c = co_await reader;
ClearLed(1);
co_await feeder.feed(std::span{&c, 1});
}
}
async::task<> blink() {
while (1) {
co_await async::delay(500);
ToggleLed(0);
timer0->Pet();
co_await UartWrite(".");
}
}
} // namespace
int main() {
gpio0 = Gpio::Instance(GPIO0_BASE);
gpio0->data = 0;
SetupUart();
UartWriteBlocking("uart setup done\r\n");
SetupTimer();
UartWriteBlocking("timer setup done\r\n");
SetupInterrupts();
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([]() {
return false;
});
// should never get here
}
/// stdlib stuff
#include <sys/time.h>
#include <cstdint>
#include "lib/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 / kTicksPerSecond + t1overflowsecs;
tv->tv_usec =
(ticks % kTicksPerSecond) / kTicksPerMicrosecond + t1overflowusecs;
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;
}