#include <sys/time.h>

#include <cstdint>

#include "itoa.h"
#include "lock.h"
#include "timer.h"
#include "uart.h"

#ifndef SBRK_STATS
#define SBRK_STATS 0
#endif

extern unsigned char _heap_begin, _heap_end;

namespace {
[[maybe_unused]]
void LogStats(unsigned char* heap) {
    char number[] = "00000000\r\n";
    UartWriteCrash("Program break now at 0x");
    itoa(reinterpret_cast<int>(heap), number);
    UartWriteCrash(number);
}
}  // namespace

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;
#if SBRK_STATS
    LogStats(heap);
#endif
    return prev_heap;
}

extern "C" int _gettimeofday(struct timeval* tv, 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) {
    auto* dest = reinterpret_cast<volatile uint8_t*>(ptr);
    bool ret;

    {
        InterruptLock lock;
        ret = *dest;
        *dest = val;
    }

    return ret;
}
