blob: f9c7b8e98283fc0e8b9ed1d15cf422e9238a1a30 [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.
// NB: Use this copy loop instead of memcpy to get word writes
// instead of byte writes.
uint32_t* itcm_base =
reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(0x0));
const uint32_t* add_uint32_m1_bin_u32 =
reinterpret_cast<const uint32_t*>(add_uint32_m1_bin);
for (unsigned int i = 0; i < add_uint32_m1_bin_len / 4; i++) {
*(itcm_base + i) = add_uint32_m1_bin_u32[i];
}
// 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;
}