|  | #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; | 
|  | } |