URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk/sw/example
- from Rev 34 to Rev 35
- ↔ Reverse comparison
Rev 34 → Rev 35
/cpu_test/main.c
49,8 → 49,6
/**@{*/ |
/** UART BAUD rate */ |
#define BAUD_RATE 19200 |
//** Set 1 to run external memory test */ |
#define EXT_MEM_TEST 1 |
//** Reachable unaligned address */ |
#define ADDR_UNALIGNED 0x00000002 |
//** Unreachable aligned address */ |
60,15 → 58,6
/**@}*/ |
|
|
/**********************************************************************//** |
* @name Exception handler acknowledges |
**************************************************************************/ |
/**@{*/ |
/** Global volatile variable to store exception handler answer */ |
volatile uint32_t exception_handler_answer; |
/**@}*/ |
|
|
// Prototypes |
void global_trap_handler(void); |
void test_ok(void); |
97,8 → 86,8
**************************************************************************/ |
int main() { |
|
register uint32_t tmp_a; |
uint32_t i; |
register uint32_t tmp_a, tmp_b, tmp_c; |
uint32_t i, j; |
volatile uint32_t dummy_dst __attribute__((unused)); |
|
union { |
115,7 → 104,7
|
neorv32_mtime_set_time(0); |
// set CMP of machine system timer MTIME to max to prevent an IRQ |
uint64_t mtime_cmp_max = 0xFFFFFFFFFFFFFFFFL; |
uint64_t mtime_cmp_max = 0xFFFFFFFFFFFFFFFFUL; |
neorv32_mtime_set_timecmp(mtime_cmp_max); |
|
// intro |
176,84 → 165,13
// intro2 |
neorv32_uart_printf("\n\nStarting tests...\n\n"); |
|
|
// enable global interrupts |
neorv32_cpu_eint(); |
|
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
|
// ---------------------------------------------------------- |
// Instruction memory test |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_uart_printf("[%i] Processor-internal IMEM test: ", cnt_test); |
|
if ((UART_CT & (1 << UART_CT_SIM_MODE)) == 0) { // check if this is a simulation |
cnt_test++; |
|
register uint32_t dmem_probe_addr = SYSINFO_ISPACE_BASE; |
uint32_t dmem_probe_cnt = 0; |
|
while(1) { |
asm volatile ("lb zero, 0(%[input_j])" : : [input_j] "r" (dmem_probe_addr)); |
if (exception_handler_answer == TRAP_CODE_L_ACCESS) { |
break; |
} |
dmem_probe_addr++; |
dmem_probe_cnt++; |
} |
|
neorv32_uart_printf("%u bytes (should be %u bytes) ", dmem_probe_cnt, SYSINFO_IMEM_SIZE); |
neorv32_uart_printf("@ 0x%x ", SYSINFO_ISPACE_BASE); |
if (dmem_probe_cnt == SYSINFO_IMEM_SIZE) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (disabled for simulation)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// Data memory test |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_uart_printf("[%i] Processor-internal DMEM test: ", cnt_test); |
|
if ((UART_CT & (1 << UART_CT_SIM_MODE)) == 0) { // check if this is a simulation |
cnt_test++; |
|
register uint32_t imem_probe_addr = SYSINFO_DSPACE_BASE; |
uint32_t imem_probe_cnt = 0; |
|
while(1) { |
asm volatile ("lb zero, 0(%[input_j])" : : [input_j] "r" (imem_probe_addr)); |
if (exception_handler_answer == TRAP_CODE_L_ACCESS) { |
break; |
} |
imem_probe_addr++; |
imem_probe_cnt++; |
} |
|
neorv32_uart_printf("%u bytes (should be %u bytes) ", imem_probe_cnt, SYSINFO_DMEM_SIZE); |
neorv32_uart_printf("@ 0x%x ", SYSINFO_DSPACE_BASE); |
if (imem_probe_cnt == SYSINFO_DMEM_SIZE) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
} |
else { |
neorv32_uart_printf("skipped (disabled for simulation)\n"); |
} |
|
|
// ---------------------------------------------------------- |
// List all accessible CSRs |
// ---------------------------------------------------------- |
neorv32_uart_printf("[%i] List all accessible CSRs: ", cnt_test); |
279,7 → 197,7
|
// iterate through full 12-bit CSR address space |
for (csr_addr_cnt=0x000; csr_addr_cnt<=0xfff; csr_addr_cnt++) { |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
// construct and store new CSR access instruction |
// 0x00006073 = csrrsi, 0x000, 0 |
292,8 → 210,8
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); |
|
// check for access exception |
if (exception_handler_answer == 0xFFFFFFFF) { // no exception -> access ok -> CSR exists |
neorv32_uart_printf(" + 0x%x\n", csr_addr_cnt); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { // no exception -> access ok -> CSR exists |
neorv32_uart_printf(" + 0x%x\n", csr_addr_cnt); |
i++; |
} |
} |
312,7 → 230,7
// ---------------------------------------------------------- |
// CFU0 test (default HW) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Default CFU0 access test: ", cnt_test); |
|
// cfu0 implemented? |
327,7 → 245,7
|
if ((CFU0_REG_0 == 0x01234567) && (CFU0_REG_1 == 0x76543210) && |
(CFU0_REG_2 == 0xABCDABCD) && (CFU0_REG_3 == 0xFFAAFFAA) && // correct read-back |
(exception_handler_answer == 0xFFFFFFFF)) { // no exception |
(neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { // no exception |
test_ok(); |
} |
else { |
335,7 → 253,7
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
neorv32_uart_printf("skipped (CFU0 not implemented)\n"); |
} |
|
|
342,7 → 260,7
// ---------------------------------------------------------- |
// CFU1 test (default HW) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Default CFU1 access test: ", cnt_test); |
|
// cfu0 implemented? |
357,7 → 275,7
|
if ((CFU1_REG_0 == 0x22334455) && (CFU1_REG_1 == 0x44782931) && |
(CFU1_REG_2 == 0xDDAABBFF) && (CFU1_REG_3 == 0xA0B0D0C0) && // correct read-back |
(exception_handler_answer == 0xFFFFFFFF)) { // no exception |
(neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { // no exception |
test_ok(); |
} |
else { |
365,7 → 283,7
} |
} |
else { |
neorv32_uart_printf("skipped (not implemented)\n"); |
neorv32_uart_printf("skipped (CFU1 not implemented)\n"); |
} |
|
|
372,7 → 290,7
// ---------------------------------------------------------- |
// Bus timeout latency estimation |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Estimate bus time-out latency: ", cnt_test); |
|
// start timing |
380,11 → 298,11
|
// this will timeout |
MMR_UNREACHABLE = 0; |
tmp_a = neorv32_cpu_csr_read(CSR_CYCLE) - tmp_a; |
|
// wait for timeout |
while (exception_handler_answer == 0xFFFFFFFF); |
while (neorv32_cpu_csr_read(CSR_MCAUSE) == 0); |
|
tmp_a = neorv32_cpu_csr_read(CSR_CYCLE) - tmp_a; |
tmp_a = tmp_a / 4; // divide by average CPI |
neorv32_uart_printf("~%u cycles\n", tmp_a); |
|
392,42 → 310,49
// ---------------------------------------------------------- |
// External memory interface test |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_uart_printf("[%i] External memory access test: ", cnt_test); |
#if (EXT_MEM_TEST == 1) |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] External memory access (@ 0x%x) test: ", cnt_test, (uint32_t)EXT_MEM_BASE); |
|
// create test program in RAM |
static const uint32_t dummy_ext_program[2] __attribute__((aligned(8))) = { |
0x3407D073, // csrwi mscratch, 15 |
0x00008067 // ret (32-bit) |
}; |
if (UART_CT & (1 << UART_CT_SIM_MODE)) { // check if this is a simulation |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT)) { |
cnt_test++; |
|
// copy to external memory |
if (memcpy((void*)EXT_MEM_BASE, (void*)&dummy_ext_program, (size_t)sizeof(dummy_ext_program)) == NULL) { |
test_fail(); |
} |
else { |
// create test program in RAM |
static const uint32_t dummy_ext_program[2] __attribute__((aligned(8))) = { |
0x3407D073, // csrwi mscratch, 15 |
0x00008067 // ret (32-bit) |
}; |
|
// execute program |
tmp_a = (uint32_t)EXT_MEM_BASE; // call the dummy sub program |
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); |
|
if (exception_handler_answer == 0xFFFFFFFF) { // make sure there was no exception |
if (neorv32_cpu_csr_read(CSR_MSCRATCH) == 15) { // make sure the program was executed in the right way |
test_ok(); |
// copy to external memory |
if (memcpy((void*)EXT_MEM_BASE, (void*)&dummy_ext_program, (size_t)sizeof(dummy_ext_program)) == NULL) { |
test_fail(); |
} |
else { |
test_fail(); |
|
// execute program |
tmp_a = (uint32_t)EXT_MEM_BASE; // call the dummy sub program |
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { // make sure there was no exception |
if (neorv32_cpu_csr_read(CSR_MSCRATCH) == 15) { // make sure the program was executed in the right way |
test_ok(); |
} |
else { |
test_fail(); |
} |
} |
else { |
test_fail(); |
} |
} |
} |
else { |
test_fail(); |
neorv32_uart_printf("skipped (external memory interface not implemented)\n"); |
} |
} |
#else |
neorv32_uart_printf("skipped (disabled)\n"); |
#endif |
else { |
neorv32_uart_printf("skipped (on real hardware)\n"); |
} |
|
|
// ---------------------------------------------------------- |
453,12 → 378,12
// ---------------------------------------------------------- |
// Test fence instructions - make sure CPU does not crash here and throws no exception |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FENCE instruction test: ", cnt_test); |
cnt_test++; |
asm volatile ("fence"); |
|
if (exception_handler_answer != 0xFFFFFFFF) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != 0) { |
test_fail(); |
} |
else { |
470,18 → 395,18
// Test fencei instructions - make sure CPU does not crash here and throws no exception |
// a more complex test is provided by the RISC-V compliance test |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FENCE.I instruction test: ", cnt_test); |
asm volatile ("fence.i"); |
|
if (exception_handler_answer == TRAP_CODE_I_ILLEGAL) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
neorv32_uart_printf("skipped (not implemented)\n"); |
} |
else { |
cnt_test++; |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
asm volatile ("fence.i"); |
if (exception_handler_answer == 0xFFFFFFFF) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
test_ok(); |
} |
else { |
493,7 → 418,7
// ---------------------------------------------------------- |
// Illegal CSR access (CSR not implemented) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Illegal CSR (0xfff) access test: ", cnt_test); |
|
cnt_test++; |
500,7 → 425,7
|
neorv32_cpu_csr_read(0xfff); // CSR 0xfff not implemented |
|
if (exception_handler_answer == TRAP_CODE_I_ILLEGAL) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
test_ok(); |
} |
else { |
511,7 → 436,7
// ---------------------------------------------------------- |
// Write-access to read-only CSR |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Read-only CSR (time) write access test: ", cnt_test); |
|
cnt_test++; |
518,7 → 443,7
|
neorv32_cpu_csr_write(CSR_TIME, 0); // time CSR is read-only |
|
if (exception_handler_answer == TRAP_CODE_I_ILLEGAL) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
test_ok(); |
} |
else { |
529,7 → 454,7
// ---------------------------------------------------------- |
// No "real" CSR write access (because rs1 = r0) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Read-only CSR (time) no-write (rs1=0) access test: ", cnt_test); |
|
cnt_test++; |
538,7 → 463,7
// -> should cause no exception |
asm volatile("csrrs zero, time, zero"); |
|
if (exception_handler_answer == 0xFFFFFFFF) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
test_ok(); |
} |
else { |
549,7 → 474,7
// ---------------------------------------------------------- |
// Unaligned instruction address |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] I_ALIGN (instruction alignment) exception test: ", cnt_test); |
|
// skip if C-mode is implemented |
560,7 → 485,7
// call unaligned address |
((void (*)(void))ADDR_UNALIGNED)(); |
|
if (exception_handler_answer == TRAP_CODE_I_MISALIGNED) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_MISALIGNED) { |
neorv32_uart_printf("ok\n"); |
cnt_ok++; |
} |
577,7 → 502,7
// ---------------------------------------------------------- |
// Instruction access fault |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] I_ACC (instruction bus access) exception test: ", cnt_test); |
cnt_test++; |
|
584,7 → 509,7
// call unreachable aligned address |
((void (*)(void))ADDR_UNREACHABLE)(); |
|
if (exception_handler_answer == TRAP_CODE_I_ACCESS) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ACCESS) { |
test_ok(); |
} |
else { |
595,7 → 520,7
// ---------------------------------------------------------- |
// Illegal instruction |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] I_ILLEG (illegal instruction) exception test: ", cnt_test); |
|
cnt_test++; |
603,7 → 528,7
asm volatile ("csrrw zero, 0xfff, zero"); // = 0xfff01073 : CSR 0xfff not implemented -> illegal instruction |
|
// make sure this has cause an illegal exception |
if (exception_handler_answer == TRAP_CODE_I_ILLEGAL) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
// make sure this is really the instruction that caused the exception |
// for illegal instructions mtval contains the actual instruction word |
if (neorv32_cpu_csr_read(CSR_MTVAL) == 0xfff01073) { |
621,7 → 546,7
// ---------------------------------------------------------- |
// Illegal compressed instruction |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] CI_ILLEG (illegal compressed instruction) exception test: ", cnt_test); |
|
// skip if C-mode is not implemented |
638,7 → 563,7
tmp_a = (uint32_t)&dummy_sub_program_ci; // call the dummy sub program |
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); |
|
if (exception_handler_answer == TRAP_CODE_I_ILLEGAL) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
test_ok(); |
} |
else { |
653,13 → 578,13
// ---------------------------------------------------------- |
// Breakpoint instruction |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] BREAK (break instruction) exception test: ", cnt_test); |
cnt_test++; |
|
asm volatile("EBREAK"); |
|
if (exception_handler_answer == TRAP_CODE_BREAKPOINT) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_BREAKPOINT) { |
test_ok(); |
} |
else { |
670,7 → 595,7
// ---------------------------------------------------------- |
// Unaligned load address |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] L_ALIGN (load address alignment) exception test: ", cnt_test); |
cnt_test++; |
|
677,7 → 602,7
// load from unaligned address |
asm volatile ("lw zero, %[input_i](zero)" : : [input_i] "i" (ADDR_UNALIGNED)); |
|
if (exception_handler_answer == TRAP_CODE_L_MISALIGNED) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_MISALIGNED) { |
test_ok(); |
} |
else { |
688,7 → 613,7
// ---------------------------------------------------------- |
// Load access fault |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] L_ACC (load bus access) exception test: ", cnt_test); |
cnt_test++; |
|
695,7 → 620,7
// load from unreachable aligned address |
dummy_dst = MMR_UNREACHABLE; |
|
if (exception_handler_answer == TRAP_CODE_L_ACCESS) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_L_ACCESS) { |
test_ok(); |
} |
else { |
706,7 → 631,7
// ---------------------------------------------------------- |
// Unaligned store address |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] S_ALIGN (store address alignment) exception test: ", cnt_test); |
cnt_test++; |
|
713,7 → 638,7
// store to unaligned address |
asm volatile ("sw zero, %[input_i](zero)" : : [input_i] "i" (ADDR_UNALIGNED)); |
|
if (exception_handler_answer == TRAP_CODE_S_MISALIGNED) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_MISALIGNED) { |
test_ok(); |
} |
else { |
724,7 → 649,7
// ---------------------------------------------------------- |
// Store access fault |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] S_ACC (store bus access) exception test: ", cnt_test); |
cnt_test++; |
|
731,7 → 656,7
// store to unreachable aligned address |
MMR_UNREACHABLE = 0; |
|
if (exception_handler_answer == TRAP_CODE_S_ACCESS) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) { |
test_ok(); |
} |
else { |
742,13 → 667,13
// ---------------------------------------------------------- |
// Environment call |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] ENVCALL (ecall instruction) exception test: ", cnt_test); |
cnt_test++; |
|
asm volatile("ECALL"); |
|
if (exception_handler_answer == TRAP_CODE_MENV_CALL) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MENV_CALL) { |
test_ok(); |
} |
else { |
759,7 → 684,7
// ---------------------------------------------------------- |
// Machine timer interrupt (MTIME) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] MTI (machine timer) interrupt test: ", cnt_test); |
|
if (neorv32_mtime_available()) { |
776,7 → 701,7
asm volatile("nop"); |
asm volatile("nop"); |
|
if (exception_handler_answer == TRAP_CODE_MTI) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_MTI) { |
test_ok(); |
} |
else { |
794,7 → 719,7
// ---------------------------------------------------------- |
// Fast interrupt channel 0 (WDT) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ0 (fast IRQ0) interrupt test (via WDT): ", cnt_test); |
|
if (neorv32_wdt_available()) { |
813,7 → 738,7
asm volatile("nop"); |
asm volatile("nop"); |
|
if (exception_handler_answer == TRAP_CODE_FIRQ_0) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_0) { |
test_ok(); |
} |
else { |
831,53 → 756,57
// ---------------------------------------------------------- |
// Fast interrupt channel 1 (GPIO) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ1 (fast IRQ1) interrupt test (via GPIO): ", cnt_test); |
|
if (neorv32_gpio_available()) { |
cnt_test++; |
if (UART_CT & (1 << UART_CT_SIM_MODE)) { // check if this is a simulation |
if (neorv32_gpio_available()) { |
cnt_test++; |
|
// clear output port |
neorv32_gpio_port_set(0); |
// clear output port |
neorv32_gpio_port_set(0); |
|
// configure GPIO.in(31) for pin-change IRQ |
neorv32_gpio_pin_change_config(0x80000000); |
// configure GPIO.in(31) for pin-change IRQ |
neorv32_gpio_pin_change_config(0x80000000); |
|
// trigger pin-change IRQ by setting GPIO.out(31) |
// the testbench connects GPIO.out => GPIO.in |
neorv32_gpio_pin_set(31); |
// trigger pin-change IRQ by setting GPIO.out(31) |
// the testbench connects GPIO.out => GPIO.in |
neorv32_gpio_pin_set(31); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
asm volatile("nop"); |
|
if (exception_handler_answer == TRAP_CODE_FIRQ_1) { |
test_ok(); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_1) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
// disable GPIO pin-change IRQ |
neorv32_gpio_pin_change_config(0); |
|
// clear output port |
neorv32_gpio_port_set(0); |
} |
else { |
test_fail(); |
neorv32_uart_printf("skipped (GPIO not implemented)\n"); |
} |
|
// disable GPIO pin-change IRQ |
neorv32_gpio_pin_change_config(0); |
|
// clear output port |
neorv32_gpio_port_set(0); |
} |
else { |
neorv32_uart_printf("skipped (GPIO not implemented)\n"); |
neorv32_uart_printf("skipped (on real hardware)\n"); |
} |
|
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 2 (UART) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ2 (fast IRQ2) interrupt test (via UART): ", cnt_test); |
|
if (neorv32_uart_available()) { |
915,7 → 844,7
// re-enable UART sim_mode if it was enabled and disable UART TX done IRQ |
UART_CT = uart_ct_backup; |
|
if (exception_handler_answer == TRAP_CODE_FIRQ_2) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_2) { |
test_ok(); |
} |
else { |
931,7 → 860,7
// ---------------------------------------------------------- |
// Fast interrupt channel 3 (SPI) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ3 (fast IRQ3) interrupt test (via SPI): ", cnt_test); |
|
if (neorv32_spi_available()) { |
952,7 → 881,7
asm volatile("nop"); |
asm volatile("nop"); |
|
if (exception_handler_answer == TRAP_CODE_FIRQ_3) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_3) { |
test_ok(); |
} |
else { |
970,16 → 899,17
// ---------------------------------------------------------- |
// Fast interrupt channel 3 (TWI) |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ3 (fast IRQ3) interrupt test (via TWI): ", cnt_test); |
|
if (neorv32_twi_available()) { |
cnt_test++; |
|
// configure TWI, fastest clock, transfer-done IRQ enable |
neorv32_twi_setup(CLK_PRSC_2, 1); |
// configure TWI, fastest clock, transfer-done IRQ enable, disable peripheral clock stretching |
neorv32_twi_setup(CLK_PRSC_2, 1, 0); |
|
// trigger TWI IRQ |
neorv32_twi_generate_start(); |
neorv32_twi_trans(0); |
neorv32_twi_generate_stop(); |
|
991,7 → 921,7
asm volatile("nop"); |
asm volatile("nop"); |
|
if (exception_handler_answer == TRAP_CODE_FIRQ_3) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_3) { |
test_ok(); |
} |
else { |
1009,7 → 939,7
// ---------------------------------------------------------- |
// Test WFI ("sleep") instructions, wakeup via MTIME |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] WFI (wait for interrupt / sleep instruction) test (wake-up via MTIME): ", cnt_test); |
|
if (neorv32_mtime_available()) { |
1021,7 → 951,7
// put CPU into sleep mode |
asm volatile ("wfi"); |
|
if (exception_handler_answer != TRAP_CODE_MTI) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_MTI) { |
test_fail(); |
} |
else { |
1039,7 → 969,7
// ---------------------------------------------------------- |
// Test invalid CSR access in user mode |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Invalid CSR access (mstatus) from user mode test: ", cnt_test); |
|
// skip if U-mode is not implemented |
1054,7 → 984,7
neorv32_cpu_csr_read(CSR_MSTATUS); |
} |
|
if (exception_handler_answer == TRAP_CODE_I_ILLEGAL) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) { |
test_ok(); |
} |
else { |
1070,7 → 1000,7
// ---------------------------------------------------------- |
// Test RTE debug handler |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] RTE (runtime environment) debug trap handler test: ", cnt_test); |
|
cnt_test++; |
1082,12 → 1012,12
neorv32_cpu_csr_read(0xfff); // CSR not available |
|
neorv32_uart_printf(" "); |
if (exception_handler_answer == 0xFFFFFFFF) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != 0) { |
test_ok(); |
} |
else { |
test_fail(); |
neorv32_uart_printf("answer: 0x%x", exception_handler_answer); |
neorv32_uart_printf("answer: 0x%x", neorv32_cpu_csr_read(CSR_MCAUSE)); |
} |
|
// restore original handler |
1097,7 → 1027,6
// ---------------------------------------------------------- |
// Test physical memory protection |
// ---------------------------------------------------------- |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_uart_printf("[%i] Physical memory protection (PMP): ", cnt_test); |
|
// check if PMP is implemented |
1105,13 → 1034,37
|
// Test access to protected region |
// --------------------------------------------- |
neorv32_uart_printf("Creating protected page (NAPOT, 64kB) @ 0xFFFFA000, [!x, !w, r]... "); |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
cnt_test++; |
|
neorv32_cpu_csr_write(CSR_PMPADDR0, 0xffffdfff); // 64k area @ 0xFFFFA000 |
neorv32_cpu_csr_write(CSR_PMPCFG0, 0b00011001); // NAPOT, read permission, NO write and NO execute permissions |
// check min granulartiy |
neorv32_cpu_csr_write(CSR_PMPCFG0, 0); |
neorv32_cpu_csr_write(CSR_PMPADDR0, 0xffffffff); |
tmp_a = neorv32_cpu_csr_read(0x3b0); |
|
if ((neorv32_cpu_csr_read(CSR_PMPADDR0) == 0xffffdfff) && (neorv32_cpu_csr_read(CSR_PMPCFG0) == 0b00011001)) { |
// find least-significat set bit |
for (i=31; i!=0; i--) { |
if (((tmp_a >> i) & 1) == 0) { |
break; |
} |
} |
|
tmp_a = SYSINFO_DSPACE_BASE; // base address of protected region |
|
tmp_b = 0; |
for (j=i; j!=0; j--) { |
tmp_b = tmp_b << 1; |
tmp_b = tmp_b | 1; |
} |
tmp_c = tmp_a & (~tmp_b); // clear LSBs in base address |
tmp_c = tmp_c | tmp_b; // set region size config |
|
neorv32_uart_printf("Creating protected page (NAPOT, [!X,!W,R], %u bytes) @ 0x%x (PMPADDR = 0x%x): ", (uint32_t)(1 << (i+1+2)), tmp_a, tmp_c); |
|
neorv32_cpu_csr_write(CSR_PMPADDR0, tmp_c); // 64k area @ 0xFFFFA000 |
neorv32_cpu_csr_write(CSR_PMPCFG0, 0b00011001); // NAPOT, read permission, NO write and NO execute permissions |
|
if ((neorv32_cpu_csr_read(CSR_PMPADDR0) == tmp_c) && (neorv32_cpu_csr_read(CSR_PMPCFG0) == 0b00011001) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
1119,18 → 1072,43
} |
|
|
// ------ EXECUTE: should fail ------ |
neorv32_uart_printf("[%i] - PMP: U-mode [!X,!W,R] execute test: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
neorv32_cpu_goto_user_mode(); |
{ |
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); // call address to execute -> should fail |
} |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
// switch back to machine mode (if not allready) |
asm volatile ("ecall"); |
|
test_fail(); |
} |
else { |
// switch back to machine mode (if not allready) |
asm volatile ("ecall"); |
|
test_ok(); |
} |
|
|
// ------ LOAD: should work ------ |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] load test: ", cnt_test); |
neorv32_uart_printf("[%i] - PMP: U-mode [!X,!W,R] read test: ", cnt_test); |
cnt_test++; |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
neorv32_cpu_goto_user_mode(); |
{ |
asm volatile ("lw zero, 0xFFFFFF90(zero)"); // MTIME load access, should work |
asm volatile ("lw zero, 0(%[input_i])" : : [input_i] "r" (tmp_a)); // load access -> should work |
} |
|
if (exception_handler_answer == 0xFFFFFFFF) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
// switch back to machine mode (if not allready) |
asm volatile ("ecall"); |
|
1145,17 → 1123,17
|
|
// ------ STORE: should fail ------ |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] store test: ", cnt_test); |
neorv32_uart_printf("[%i] - PMP: U-mode [!X,!W,R] write test: ", cnt_test); |
cnt_test++; |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
// switch to user mode (hart will be back in MACHINE mode when trap handler returns) |
neorv32_cpu_goto_user_mode(); |
{ |
asm volatile ("sw zero, 0xFFFFFF90(zero)"); // MTIME store access, should fail |
asm volatile ("sw zero, 0(%[input_i])" : : [input_i] "r" (tmp_a)); // store access -> should fail |
} |
|
if (exception_handler_answer == TRAP_CODE_S_ACCESS) { |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) { |
// switch back to machine mode (if not allready) |
asm volatile ("ecall"); |
|
1169,18 → 1147,18
} |
|
|
// ------ Lock test ------ |
neorv32_uart_printf("[%i] PMP: Locking pmpcfg0 [mode=off]: ", cnt_test); |
// ------ Lock test - pmpcfg0.0 ------ |
neorv32_uart_printf("[%i] - PMP: pmpcfg0.0 [mode=off] lock test: ", cnt_test); |
cnt_test++; |
exception_handler_answer = 0xFFFFFFFF; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
neorv32_cpu_csr_write(CSR_PMPCFG0, 0b10000001); // locked but entry is deactivated (mode = off) |
neorv32_cpu_csr_write(CSR_PMPCFG0, 0b10000001); // locked, but entry is deactivated (mode = off) |
|
// make sure a locked cfg cannot be written |
tmp_a = neorv32_cpu_csr_read(CSR_PMPCFG0); |
neorv32_cpu_csr_write(CSR_PMPCFG0, 0b00011001); // try to re-write CFG content |
|
if ((tmp_a != neorv32_cpu_csr_read(CSR_PMPCFG0)) || (exception_handler_answer != 0xFFFFFFFF)) { |
if ((tmp_a != neorv32_cpu_csr_read(CSR_PMPCFG0)) || (neorv32_cpu_csr_read(CSR_MCAUSE) != 0)) { |
test_fail(); |
} |
else { |
1187,6 → 1165,25
test_ok(); |
} |
|
|
// ------ Lock test - pmpaddr0 ------ |
neorv32_uart_printf("[%i] - PMP: pmpaddr0 [mode=off] lock test: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
neorv32_cpu_csr_write(CSR_PMPCFG0, 0b10000001); // locked, but entry is deactivated (mode = off) |
|
// make sure a locked cfg cannot be written |
tmp_a = neorv32_cpu_csr_read(CSR_PMPADDR0); |
neorv32_cpu_csr_write(CSR_PMPADDR0, 0xABABCDCD); // try to re-write ADDR content |
|
if ((tmp_a != neorv32_cpu_csr_read(CSR_PMPADDR0)) || (neorv32_cpu_csr_read(CSR_MCAUSE) != 0)) { |
test_fail(); |
} |
else { |
test_ok(); |
} |
|
} |
else { |
neorv32_uart_printf("not implemented\n"); |
1196,17 → 1193,17
// ---------------------------------------------------------- |
// Final test reports |
// ---------------------------------------------------------- |
neorv32_uart_printf("\n\nExecuted instructions: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET)); |
neorv32_uart_printf( "Required clock cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_CYCLE)); |
neorv32_uart_printf("\nExecuted instructions: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_INSTRET)); |
neorv32_uart_printf( "Required clock cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_CYCLE)); |
|
neorv32_uart_printf("\nTest results:\nOK: %i/%i\nFAILED: %i/%i\n\n", cnt_ok, cnt_test, cnt_fail, cnt_test); |
|
// final result |
if (cnt_fail == 0) { |
neorv32_uart_printf("%c[1mTEST OK!%c[0m\n", 27, 27); |
neorv32_uart_printf("%c[1m[TEST OK!]%c[0m\n", 27, 27); |
} |
else { |
neorv32_uart_printf("%c[1mTEST FAILED!%c[0m\n", 27, 27); |
neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27); |
} |
|
return 0; |
1218,8 → 1215,6
**************************************************************************/ |
void global_trap_handler(void) { |
|
exception_handler_answer = neorv32_cpu_csr_read(CSR_MCAUSE); |
|
// hack: always come back in MACHINE MODE |
register uint32_t mask = (1<<CPU_MSTATUS_MPP_H) | (1<<CPU_MSTATUS_MPP_L); |
asm volatile ("csrrs zero, mstatus, %[input_j]" : : [input_j] "r" (mask)); |
/demo_twi/main.c
60,9 → 60,9
|
|
/**********************************************************************//** |
* This program generates a simple dimming sequence for PWM channel 0,1,2. |
* This program provides an interactive console to communicate with TWI devices. |
* |
* @note This program requires the UART and the TWI to be synthesized. |
* @note This program requires the UART and the PWM to be synthesized. |
* |
* @return Irrelevant. |
**************************************************************************/ |
101,8 → 101,8
neorv32_uart_printf("This program allows to create TWI transfers by hand.\n" |
"Type 'help' to see the help menu.\n\n"); |
|
// configure TWI, second slowest clock, no IRQ |
neorv32_twi_setup(CLK_PRSC_2048, 0); |
// configure TWI, second slowest clock, no IRQ, no clock-stretching |
neorv32_twi_setup(CLK_PRSC_2048, 0, 0); |
|
// no active bus session yet |
bus_claimed = 0; |
/hex_viewer/main.c
0,0 → 1,271
// ################################################################################################# |
// # << NEORV32 - Hex Viewer - Memory Inspector >> # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
// # # |
// # 1. Redistributions of source code must retain the above copyright notice, this list of # |
// # conditions and the following disclaimer. # |
// # # |
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
// # conditions and the following disclaimer in the documentation and/or other materials # |
// # provided with the distribution. # |
// # # |
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
// # endorse or promote products derived from this software without specific prior written # |
// # permission. # |
// # # |
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
// # OF THE POSSIBILITY OF SUCH DAMAGE. # |
// # ********************************************************************************************* # |
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file hex_viewer/main.c |
* @author Stephan Nolting |
* @brief Interactive memory inspector. |
**************************************************************************/ |
|
#include <neorv32.h> |
#include <string.h> |
|
|
/**********************************************************************//** |
* @name User configuration |
**************************************************************************/ |
/**@{*/ |
/** UART BAUD rate */ |
#define BAUD_RATE 19200 |
/**@}*/ |
|
|
// Prototypes |
void read_memory(void); |
void write_memory(void); |
void dump_memory(void); |
uint32_t hexstr_to_uint(char *buffer, uint8_t length); |
|
|
/**********************************************************************//** |
* This program provides an interactive console to read/write memory. |
* |
* @note This program requires the UART to be synthesized. |
* |
* @return Irrelevant. |
**************************************************************************/ |
int main() { |
|
char buffer[8]; |
int length = 0; |
|
// check if UART unit is implemented at all |
if (neorv32_uart_available() == 0) { |
return 0; |
} |
|
|
// capture all exceptions and give debug info via UART |
neorv32_rte_setup(); |
|
|
// init UART at default baud rate, no rx interrupt, no tx interrupt |
neorv32_uart_setup(BAUD_RATE, 0, 0); |
|
// intro |
neorv32_uart_printf("\n--- Hex Viewer ---\n\n"); |
|
// info |
neorv32_uart_printf("This program allows to read/write/dump memory locations by hand.\n" |
"Type 'help' to see the help menu.\n\n"); |
|
// Main menu |
for (;;) { |
neorv32_uart_printf("HEX_VIEWER:> "); |
length = neorv32_uart_scan(buffer, 8, 1); |
neorv32_uart_printf("\n"); |
|
if (!length) // nothing to be done |
continue; |
|
// decode input and execute command |
if (!strcmp(buffer, "help")) { |
neorv32_uart_printf("Available commands:\n" |
" help - show this text\n" |
" read - read single word from address\n" |
" write - write single word to address\n" |
" dump - dumpe several words from base address\n\n"); |
} |
|
else if (!strcmp(buffer, "read")) { |
read_memory(); |
} |
|
else if (!strcmp(buffer, "write")) { |
write_memory(); |
} |
|
else if (!strcmp(buffer, "dump")) { |
dump_memory(); |
} |
|
else { |
neorv32_uart_printf("Invalid command. Type 'help' to see all commands.\n"); |
} |
} |
|
return 0; |
} |
|
|
/**********************************************************************//** |
* Read word from memory address |
**************************************************************************/ |
void read_memory(void) { |
|
char terminal_buffer[16]; |
|
// enter address |
neorv32_uart_printf("Enter address (8 hex chars): "); |
neorv32_uart_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0' |
register uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
mem_address = mem_address & 0xFFFFFFFCUL; // align to 32-bit boundary |
|
// perform read access |
neorv32_uart_printf("\n[0x%x] = ", mem_address); |
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
register uint32_t mem_data = 0; |
|
asm volatile ("lw %[rdata], 0(%[raddr])" : [rdata] "=r" (mem_data) : [raddr] "r" (mem_address)); |
|
// show memory content if there was no exception |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
neorv32_uart_printf("0x%x", mem_data); |
} |
|
neorv32_uart_printf("\n"); |
} |
|
|
/**********************************************************************//** |
* Write word tp memory address |
**************************************************************************/ |
void write_memory(void) { |
|
char terminal_buffer[16]; |
|
// enter address |
neorv32_uart_printf("Enter address (8 hex chars): "); |
neorv32_uart_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0' |
register uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
mem_address = mem_address & 0xFFFFFFFCUL; // align to 32-bit boundary |
|
// enter data |
neorv32_uart_printf("\nEnter data (8 hex chars): "); |
neorv32_uart_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0' |
register uint32_t mem_data = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
|
// perform write access |
neorv32_uart_printf("\n[0x%x] = ", mem_address); |
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
asm volatile ("sw %[wdata], 0(%[waddr])" : : [wdata] "r" (mem_data), [waddr] "r" (mem_address)); |
asm volatile ("nop"); |
|
// show memory content if there was no exception |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
neorv32_uart_printf("0x%x", mem_data); |
} |
|
neorv32_uart_printf("\n"); |
} |
|
|
/**********************************************************************//** |
* Read several words from memory base address |
**************************************************************************/ |
void dump_memory(void) { |
|
char terminal_buffer[16]; |
|
// enter base address |
neorv32_uart_printf("Enter base address (8 hex chars): "); |
neorv32_uart_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0' |
register uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
mem_address = mem_address & 0xFFFFFFFCUL; // align to 32-bit boundary |
|
neorv32_uart_printf("\nPress key to start dumping. Press any key to abort.\n"); |
|
neorv32_uart_getc(); // wait for key |
|
// perform read accesses |
register uint32_t mem_data = 0; |
while(neorv32_uart_char_received() == 0) { |
|
neorv32_uart_printf("[0x%x] = ", mem_address); |
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
asm volatile ("lw %[rdata], 0(%[raddr])" : [rdata] "=r" (mem_data) : [raddr] "r" (mem_address)); |
asm volatile ("nop"); |
|
// show memory content if there was no exception |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
neorv32_uart_printf("0x%x\n", mem_data); |
} |
else { |
break; |
} |
|
mem_address = mem_address + 4; |
|
} |
neorv32_uart_char_received_get(); // clear UART rx buffer |
neorv32_uart_printf("\n"); |
} |
|
|
/**********************************************************************//** |
* Helper function to convert N hex chars string into uint32_T |
* |
* @param[in,out] buffer Pointer to array of chars to convert into number. |
* @param[in,out] length Length of the conversion string. |
* @return Converted number. |
**************************************************************************/ |
uint32_t hexstr_to_uint(char *buffer, uint8_t length) { |
|
uint32_t res = 0, d = 0; |
char c = 0; |
|
while (length--) { |
c = *buffer++; |
|
if ((c >= '0') && (c <= '9')) |
d = (uint32_t)(c - '0'); |
else if ((c >= 'a') && (c <= 'f')) |
d = (uint32_t)((c - 'a') + 10); |
else if ((c >= 'A') && (c <= 'F')) |
d = (uint32_t)((c - 'A') + 10); |
else |
d = 0; |
|
res = res + (d << (length*4)); |
} |
|
return res; |
} |
/hex_viewer/makefile
0,0 → 1,338
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
# # |
# 1. Redistributions of source code must retain the above copyright notice, this list of # |
# conditions and the following disclaimer. # |
# # |
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
# conditions and the following disclaimer in the documentation and/or other materials # |
# provided with the distribution. # |
# # |
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
# endorse or promote products derived from this software without specific prior written # |
# permission. # |
# # |
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
# OF THE POSSIBILITY OF SUCH DAMAGE. # |
# ********************************************************************************************* # |
# The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
################################################################################################# |
|
|
# ***************************************************************************** |
# USER CONFIGURATION |
# ***************************************************************************** |
# User's application sources (*.c, *.cpp, *.s, *.S); add additional files here |
APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) |
|
# User's application include folders (don't forget the '-I' before each entry) |
APP_INC ?= -I . |
# User's application include folders - for assembly files only (don't forget the '-I' before each entry) |
ASM_INC ?= -I . |
|
# Optimization |
EFFORT ?= -Os |
|
# Compiler toolchain |
RISCV_TOOLCHAIN ?= riscv32-unknown-elf |
|
# CPU architecture and ABI |
MARCH ?= -march=rv32i |
MABI ?= -mabi=ilp32 |
|
# User flags for additional configuration (will be added to compiler flags) |
USER_FLAGS ?= |
|
# Serial port for executable upload via bootloer |
COM_PORT ?= /dev/ttyUSB0 |
|
# Relative or absolute path to the NEORV32 home folder |
NEORV32_HOME ?= ../../.. |
# ***************************************************************************** |
|
|
|
# ----------------------------------------------------------------------------- |
# NEORV32 framework |
# ----------------------------------------------------------------------------- |
# Path to NEORV32 linker script and startup file |
NEORV32_COM_PATH = $(NEORV32_HOME)/sw/common |
# Path to main NEORV32 library include files |
NEORV32_INC_PATH = $(NEORV32_HOME)/sw/lib/include |
# Path to main NEORV32 library source files |
NEORV32_SRC_PATH = $(NEORV32_HOME)/sw/lib/source |
# Path to NEORV32 executable generator |
NEORV32_EXG_PATH = $(NEORV32_HOME)/sw/image_gen |
# Path to NEORV32 core rtl folder |
NEORV32_RTL_PATH = $(NEORV32_HOME)/rtl/core |
# Marker file to check for NEORV32 home folder |
NEORV32_HOME_MARKER = $(NEORV32_INC_PATH)/neorv32.h |
|
# Core libraries (peripheral and CPU drivers) |
CORE_SRC = $(wildcard $(NEORV32_SRC_PATH)/*.c) |
# Application start-up code |
CORE_SRC += $(NEORV32_COM_PATH)/crt0.S |
|
# Linker script |
LD_SCRIPT = $(NEORV32_COM_PATH)/neorv32.ld |
|
# Main output files |
APP_EXE = neorv32_exe.bin |
APP_ASM = main.asm |
APP_IMG = neorv32_application_image.vhd |
BOOT_IMG = neorv32_bootloader_image.vhd |
|
|
# ----------------------------------------------------------------------------- |
# Sources and objects |
# ----------------------------------------------------------------------------- |
# Define all sources |
SRC = $(APP_SRC) |
SRC += $(CORE_SRC) |
|
# Define all object files |
OBJ = $(SRC:%=%.o) |
|
|
# ----------------------------------------------------------------------------- |
# Tools and flags |
# ----------------------------------------------------------------------------- |
# Compiler tools |
CC = $(RISCV_TOOLCHAIN)-gcc |
OBJDUMP = $(RISCV_TOOLCHAIN)-objdump |
OBJCOPY = $(RISCV_TOOLCHAIN)-objcopy |
SIZE = $(RISCV_TOOLCHAIN)-size |
|
# Host native compiler |
CC_X86 = gcc -Wall -O -g |
|
# NEORV32 executable image generator |
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
CC_OPTS += $(USER_FLAGS) |
|
|
# ----------------------------------------------------------------------------- |
# Application output definitions |
# ----------------------------------------------------------------------------- |
.PHONY: check info help elf_info clean clean_all bootloader |
.DEFAULT_GOAL := help |
|
# 'compile' is still here for compatibility |
exe: $(APP_ASM) $(APP_EXE) |
compile: $(APP_ASM) $(APP_EXE) |
install: $(APP_ASM) $(APP_IMG) |
all: $(APP_ASM) $(APP_EXE) $(APP_IMG) |
|
# Check if making bootloader |
# Use different base address and legth for instruction memory/"rom" (BOOTMEM instead of IMEM) |
# Also define "make_bootloader" for crt0.S |
target bootloader: CC_OPTS += -Wl,--defsym=make_bootloader=1 -Dmake_bootloader |
|
|
# ----------------------------------------------------------------------------- |
# Image generator targets |
# ----------------------------------------------------------------------------- |
# install/compile tools |
$(IMAGE_GEN): $(NEORV32_EXG_PATH)/image_gen.cpp |
@echo Compiling $(IMAGE_GEN) |
@$(CC_X86) $< -o $(IMAGE_GEN) |
|
|
# ----------------------------------------------------------------------------- |
# General targets: Assemble, compile, link, dump |
# ----------------------------------------------------------------------------- |
# Compile app *.s sources (assembly) |
%.s.o: %.s |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@ |
|
# Compile app *.S sources (assembly + C pre-processor) |
%.S.o: %.S |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@ |
|
# Compile app *.c sources |
%.c.o: %.c |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@ |
|
# Compile app *.cpp sources |
%.cpp.o: %.cpp |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@ |
|
# Link object files and show memory utilization |
main.elf: $(OBJ) |
@$(CC) $(CC_OPTS) -T $(LD_SCRIPT) $(OBJ) -o $@ |
@echo "Memory utilization:" |
@$(SIZE) main.elf |
|
# Assembly listing file (for debugging) |
$(APP_ASM): main.elf |
@$(OBJDUMP) -D -S -z $< > $@ |
|
# Generate final executable from .text + .rodata + .data (in THIS order!) |
main.bin: main.elf $(APP_ASM) |
@$(OBJCOPY) -I elf32-little $< -j .text -O binary text.bin |
@$(OBJCOPY) -I elf32-little $< -j .rodata -O binary rodata.bin |
@$(OBJCOPY) -I elf32-little $< -j .data -O binary data.bin |
@cat text.bin rodata.bin data.bin > $@ |
@rm -f text.bin rodata.bin data.bin |
|
|
# ----------------------------------------------------------------------------- |
# Application targets: Generate binary executable, install (as VHDL file) |
# ----------------------------------------------------------------------------- |
# Generate NEORV32 executable image for upload via bootloader |
$(APP_EXE): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -app_bin $< $@ $(shell basename $(CURDIR)) |
@echo "Executable ($(APP_EXE)) size in bytes:" |
@wc -c < $(APP_EXE) |
|
# Generate NEORV32 executable VHDL boot image |
$(APP_IMG): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -app_img $< $@ $(shell basename $(CURDIR)) |
@echo "Installing application image to $(NEORV32_RTL_PATH)/$(APP_IMG)" |
@cp $(APP_IMG) $(NEORV32_RTL_PATH)/. |
|
|
# ----------------------------------------------------------------------------- |
# Bootloader targets |
# ----------------------------------------------------------------------------- |
# Create and install bootloader VHDL init image |
$(BOOT_IMG): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -bld_img $< $(BOOT_IMG) $(shell basename $(CURDIR)) |
@echo "Installing bootloader image to $(NEORV32_RTL_PATH)/$(BOOT_IMG)" |
@cp $(BOOT_IMG) $(NEORV32_RTL_PATH)/. |
|
# Just an alias that |
bootloader: $(BOOT_IMG) |
|
|
# ----------------------------------------------------------------------------- |
# Check toolchain |
# ----------------------------------------------------------------------------- |
check: $(IMAGE_GEN) |
@echo "---------------- Check: NEORV32_HOME folder ----------------" |
ifneq ($(shell [ -e $(NEORV32_HOME_MARKER) ] && echo 1 || echo 0 ), 1) |
$(error NEORV32_HOME folder not found!) |
endif |
@echo "NEORV32_HOME: $(NEORV32_HOME)" |
@echo "---------------- Check: $(CC) ----------------" |
@$(CC) -v |
@echo "---------------- Check: $(OBJDUMP) ----------------" |
@$(OBJDUMP) -V |
@echo "---------------- Check: $(OBJCOPY) ----------------" |
@$(OBJCOPY) -V |
@echo "---------------- Check: $(SIZE) ----------------" |
@$(SIZE) -V |
@echo "---------------- Check: NEORV32 image_gen ----------------" |
@$(IMAGE_GEN) -help |
@echo "---------------- Check: Native GCC ----------------" |
@$(CC_X86) -v |
@echo |
@echo "Toolchain check OK" |
|
|
# ----------------------------------------------------------------------------- |
# Upload executable via serial port to bootloader |
# ----------------------------------------------------------------------------- |
upload: $(APP_EXE) |
@sh $(NEORV32_EXG_PATH)/uart_upload.sh $(COM_PORT) $(APP_EXE) |
|
|
# ----------------------------------------------------------------------------- |
# Show configuration |
# ----------------------------------------------------------------------------- |
info: |
@echo "---------------- Info: Project ----------------" |
@echo "Project folder: $(shell basename $(CURDIR))" |
@echo "Source files: $(APP_SRC)" |
@echo "Include folder(s): $(APP_INC)" |
@echo "ASM include folder(s): $(ASM_INC)" |
@echo "---------------- Info: NEORV32 ----------------" |
@echo "NEORV32 home folder (NEORV32_HOME): $(NEORV32_HOME)" |
@echo "IMAGE_GEN: $(IMAGE_GEN)" |
@echo "Core source files:" |
@echo "$(CORE_SRC)" |
@echo "Core include folder:" |
@echo "$(NEORV32_INC_PATH)" |
@echo "---------------- Info: Objects ----------------" |
@echo "Project object files:" |
@echo "$(OBJ)" |
@echo "---------------- Info: RISC-V CPU ----------------" |
@echo "MARCH: $(MARCH)" |
@echo "MABI: $(MABI)" |
@echo "---------------- Info: Toolchain ----------------" |
@echo "Toolchain: $(RISCV_TOLLCHAIN)" |
@echo "CC: $(CC)" |
@echo "OBJDUMP: $(OBJDUMP)" |
@echo "OBJCOPY: $(OBJCOPY)" |
@echo "SIZE: $(SIZE)" |
@echo "---------------- Info: Compiler Libraries ----------------" |
@echo "LIBGCC:" |
@$(CC) -print-libgcc-file-name |
@echo "SEARCH-DIRS:" |
@$(CC) -print-search-dirs |
@echo "---------------- Info: Flags ----------------" |
@echo "USER_FLAGS: $(USER_FLAGS)" |
@echo "CC_OPTS: $(CC_OPTS)" |
@echo "---------------- Info: Host Native GCC Flags ----------------" |
@echo "CC_X86: $(CC_X86)" |
|
|
# ----------------------------------------------------------------------------- |
# Show final ELF details (just for debugging) |
# ----------------------------------------------------------------------------- |
elf_info: main.elf |
@$(OBJDUMP) -x main.elf |
|
|
# ----------------------------------------------------------------------------- |
# Help |
# ----------------------------------------------------------------------------- |
help: |
@echo "<<< NEORV32 Application Makefile >>>" |
@echo "Make sure to add the bin folder of RISC-V GCC to your PATH variable." |
@echo "Targets:" |
@echo " help - show this text" |
@echo " check - check toolchain" |
@echo " info - show makefile/toolchain configuration" |
@echo " exe - compile and generate <neorv32_exe.bin> executable for upload via bootloader" |
@echo " install - compile, generate and install VHDL IMEM boot image (for application)" |
@echo " all - compile and generate <neorv32_exe.bin> executable for upload via bootloader and generate and install VHDL IMEM boot image (for application)" |
@echo " clean - clean up project" |
@echo " clean_all - clean up project, core libraries and image generator" |
@echo " bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only!)" |
@echo " upload - upload <neorv32_exe.bin> executable via serial port <COM_PORT> to bootloader" |
|
|
# ----------------------------------------------------------------------------- |
# Clean up |
# ----------------------------------------------------------------------------- |
clean: |
@rm -f *.elf *.o *.bin *.out *.asm *.vhd |
|
clean_all: clean |
@rm -f $(OBJ) $(IMAGE_GEN) |