#define UART_BASE 0xc010
#define UART_DATA   ((volatile char*) (UART_BASE + 0x00))
#define UART_STATUS ((volatile char*) (UART_BASE + 0x02))

#define UART_STATUS_RXNE_pos 1
#define UART_STATUS_RXNE_msk (1 << UART_STATUS_RXNE_pos)
#define UART_STATUS_TXE_pos  0
#define UART_STATUS_TXE_msk  (1 << UART_STATUS_TXE_pos)

const char hello[] = "Hello, world!";

int uart_tx_available() {
  return (*UART_STATUS & UART_STATUS_TXE_msk) != 0;
}

void uart_send(const char* data, int len) {
  for (int i = 0; i < len; ++i) {
    while (!uart_tx_available()) {
    }

    *UART_DATA = data[i];
  }
}

int main() {
  uart_send(hello, sizeof(hello));

  while (1) {
  }

  // never returns
}