blob: 3ff561f503fa23288708fbfebc82c035a744db54 [file] [log] [blame]
#include <stdint.h>
#include <cstring>
#include "fpga/add_uint32_m1_bin_header.h"
extern "C" int main() {
// Copy the embedded binary to Kelvin's ITCM at 0x0.
void *itcm_base = reinterpret_cast<void *>(static_cast<uintptr_t>(0x0));
memcpy(itcm_base, add_uint32_m1_bin, add_uint32_m1_bin_len);
// Kelvin run sequence
volatile unsigned int *kelvin_reset_csr =
reinterpret_cast<volatile unsigned int *>(
static_cast<uintptr_t>(0x00030000));
// Release clock gate
*kelvin_reset_csr = 1;
// Wait one cycle
__asm__ volatile("nop");
// Release reset
*kelvin_reset_csr = 0;
volatile unsigned int *kelvin_status_csr =
reinterpret_cast<volatile unsigned int *>(
static_cast<uintptr_t>(0x00030008));
// Wait for Kelvin to halt
while (!(*kelvin_status_csr & 1)) {
for (int i = 0; i < 1000; ++i) {
__asm__ volatile("nop");
}
}
// Configure UART0.
// The NCO is calculated as: (baud_rate * 2^20) / clock_frequency
// In our case: (115200 * 2^20) / (CLOCK_FREQUENCY_MHZ * 1000000)
volatile unsigned int *uart_ctrl =
reinterpret_cast<volatile unsigned int *>(0x40000010);
const uint64_t uart_ctrl_nco =
((uint64_t)115200 << 20) / (CLOCK_FREQUENCY_MHZ * 1000000);
// Enable TX and RX, and set the NCO value.
*uart_ctrl = (uart_ctrl_nco << 16) | 3;
auto uart_print = [](const char *str) {
volatile char *uart_wdata = reinterpret_cast<volatile char *>(0x4000001c);
volatile unsigned int *uart_status =
reinterpret_cast<volatile unsigned int *>(0x40000014);
while (*str) {
// Wait until TX FIFO is not full.
while (*uart_status & 1) {
asm volatile("nop");
}
*uart_wdata = *str++;
}
};
uart_print("Kelvin halted, as expected.\n");
volatile unsigned int *sram = (volatile unsigned int *)0x20000000;
*sram = 0xdeadbeef;
while (*sram != 0xdeadbeef) {
asm volatile("nop");
}
return 0;
}