mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-24 14:17:51 -04:00
[sw\example\cpu_test] clean-up; added HPM tests
This commit is contained in:
parent
50a777cd9b
commit
31b7b929b9
1 changed files with 62 additions and 130 deletions
|
@ -3,7 +3,7 @@
|
|||
// # ********************************************************************************************* #
|
||||
// # BSD 3-Clause License #
|
||||
// # #
|
||||
// # Copyright (c) 2020, Stephan Nolting. All rights reserved. #
|
||||
// # Copyright (c) 2021, 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: #
|
||||
|
@ -74,6 +74,8 @@ int cnt_ok = 0;
|
|||
int cnt_test = 0;
|
||||
/// Global timestamp for traps (stores mcycle.low on trap enter)
|
||||
uint32_t trap_timestamp32 = 0;
|
||||
/// Global numbe rof available HPMs
|
||||
uint32_t num_hpm_cnts_global = 0;
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
|
@ -122,14 +124,8 @@ void sim_trigger_mei(void) {
|
|||
int main() {
|
||||
|
||||
register uint32_t tmp_a, tmp_b;
|
||||
int i;
|
||||
volatile uint32_t dummy_dst __attribute__((unused));
|
||||
|
||||
union {
|
||||
uint64_t uint64;
|
||||
uint32_t uint32[sizeof(uint64_t)/2];
|
||||
} cpu_systime;
|
||||
|
||||
|
||||
// init UART at default baud rate, no parity bits, no rx interrupt, no tx interrupt
|
||||
neorv32_uart_setup(BAUD_RATE, 0b00, 0, 0);
|
||||
|
@ -181,9 +177,6 @@ int main() {
|
|||
// show project credits
|
||||
neorv32_rte_print_credits();
|
||||
|
||||
// show project license
|
||||
neorv32_rte_print_license();
|
||||
|
||||
// show full HW config report
|
||||
neorv32_rte_print_hw_config();
|
||||
|
||||
|
@ -240,63 +233,6 @@ int main() {
|
|||
neorv32_cpu_eint();
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// List all accessible CSRs
|
||||
// ----------------------------------------------------------
|
||||
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
||||
neorv32_uart_printf("[%i] List all accessible CSRs: ", cnt_test);
|
||||
|
||||
if ((UART_CT & (1 << UART_CT_SIM_MODE)) == 0) { // check if this is a simulation
|
||||
|
||||
cnt_test++;
|
||||
i = 0;
|
||||
|
||||
neorv32_uart_printf("\n");
|
||||
|
||||
uint32_t csr_addr_cnt = 0;
|
||||
|
||||
// create test program in RAM
|
||||
static const uint32_t csr_access_test_program[2] __attribute__((aligned(8))) = {
|
||||
0x00006073, // csrrsi, 0x000, 0
|
||||
0x00008067 // ret (32-bit)
|
||||
};
|
||||
|
||||
// base address of program
|
||||
tmp_a = (uint32_t)&csr_access_test_program;
|
||||
uint32_t *csr_pnt = (uint32_t*)tmp_a;
|
||||
|
||||
// iterate through full 12-bit CSR address space
|
||||
for (csr_addr_cnt=0x000; csr_addr_cnt<=0xfff; csr_addr_cnt++) {
|
||||
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
||||
|
||||
// construct and store new CSR access instruction
|
||||
// 0x00006073 = csrrsi, 0x000, 0
|
||||
*csr_pnt = 0x00006073 | (csr_addr_cnt << 20); // insert current CSR address into most significant 12 bits
|
||||
|
||||
// sync instruction stream
|
||||
asm volatile("fence.i");
|
||||
|
||||
// execute test program
|
||||
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a));
|
||||
|
||||
// check for access exception
|
||||
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { // no exception -> access ok -> CSR exists
|
||||
neorv32_uart_printf(" + 0x%x\n", csr_addr_cnt);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (i != 0) { // at least one CSR was accessible
|
||||
test_ok();
|
||||
}
|
||||
else {
|
||||
test_fail();
|
||||
}
|
||||
}
|
||||
else {
|
||||
neorv32_uart_printf("skipped (disabled for simulation)\n");
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Test standard RISC-V performance counter [m]cycle[h]
|
||||
// ----------------------------------------------------------
|
||||
|
@ -424,6 +360,43 @@ int main() {
|
|||
neorv32_cpu_csr_write(CSR_MCOUNTEREN, tmp_a);
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Test performance counter: setup as many events and counter as feasible
|
||||
// ----------------------------------------------------------
|
||||
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
||||
neorv32_uart_printf("[%i] Initializing HPMs: ", cnt_test);
|
||||
|
||||
num_hpm_cnts_global = neorv32_cpu_hpm_get_counters();
|
||||
|
||||
if (num_hpm_cnts_global != 0) {
|
||||
cnt_test++;
|
||||
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER3, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT3, 1 << HPMCNT_EVENT_CIR);
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER4, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT4, 1 << HPMCNT_EVENT_WAIT_IF);
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER5, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT5, 1 << HPMCNT_EVENT_LOAD);
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER6, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT6, 1 << HPMCNT_EVENT_STORE);
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER7, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT7, 1 << HPMCNT_EVENT_WAIT_LS);
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER8, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT8, 1 << HPMCNT_EVENT_JUMP);
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER9, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT9, 1 << HPMCNT_EVENT_BRANCH);
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER10, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT10, 1 << HPMCNT_EVENT_TBRANCH);
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER11, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT11, 1 << HPMCNT_EVENT_TRAP);
|
||||
neorv32_cpu_csr_write(CSR_MHPMCOUNTER12, 0); neorv32_cpu_csr_write(CSR_MHPMEVENT12, 1 << HPMCNT_EVENT_ILLEGAL);
|
||||
|
||||
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, 0); // enable all counters
|
||||
|
||||
// make sure there was no exception
|
||||
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
|
||||
test_ok();
|
||||
}
|
||||
else {
|
||||
test_fail();
|
||||
}
|
||||
}
|
||||
else {
|
||||
neorv32_uart_printf("skipped (not implemented)\n");
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Bus timeout latency estimation
|
||||
// ----------------------------------------------------------
|
||||
|
@ -435,9 +408,9 @@ int main() {
|
|||
neorv32_cpu_csr_write(CSR_MCYCLE, 0);
|
||||
|
||||
// this store access will timeout
|
||||
MMR_UNREACHABLE = 0; // trap handler will stor mcycle.low to "trap_timestamp32"
|
||||
MMR_UNREACHABLE = 0; // trap handler will store mcycle.low to "trap_timestamp32"
|
||||
|
||||
// make sure there was a time-out
|
||||
// make sure there was a timeout
|
||||
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_S_ACCESS) {
|
||||
neorv32_uart_printf("~%u cycles ", trap_timestamp32-178); // remove trap handler overhead - empiric value ;)
|
||||
test_ok();
|
||||
|
@ -495,66 +468,6 @@ int main() {
|
|||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Test time (must be == MTIME.TIME)
|
||||
// ----------------------------------------------------------
|
||||
neorv32_uart_printf("[%i] Time (MTIME.time vs CSR.time) sync: ", cnt_test);
|
||||
cnt_test++;
|
||||
|
||||
cpu_systime.uint64 = neorv32_cpu_get_systime();
|
||||
uint64_t mtime_systime = neorv32_mtime_get_time();
|
||||
|
||||
// compute difference
|
||||
mtime_systime = mtime_systime - cpu_systime.uint64;
|
||||
|
||||
if (mtime_systime < 4096) { // diff should be pretty small depending on bus latency
|
||||
test_ok();
|
||||
}
|
||||
else {
|
||||
test_fail();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Test fence instructions - make sure CPU does not crash here and throws no exception
|
||||
// ----------------------------------------------------------
|
||||
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
||||
neorv32_uart_printf("[%i] FENCE instruction test: ", cnt_test);
|
||||
cnt_test++;
|
||||
asm volatile ("fence");
|
||||
|
||||
if (neorv32_cpu_csr_read(CSR_MCAUSE) != 0) {
|
||||
test_fail();
|
||||
}
|
||||
else {
|
||||
test_ok();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 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
|
||||
// ----------------------------------------------------------
|
||||
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
||||
neorv32_uart_printf("[%i] FENCE.I instruction test: ", cnt_test);
|
||||
asm volatile ("fence.i");
|
||||
|
||||
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_I_ILLEGAL) {
|
||||
neorv32_uart_printf("skipped (not implemented)\n");
|
||||
}
|
||||
else {
|
||||
cnt_test++;
|
||||
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
|
||||
asm volatile ("fence.i");
|
||||
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
|
||||
test_ok();
|
||||
}
|
||||
else {
|
||||
test_fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Illegal CSR access (CSR not implemented)
|
||||
// ----------------------------------------------------------
|
||||
|
@ -1324,7 +1237,7 @@ int main() {
|
|||
neorv32_uart_printf("[%i] Physical memory protection (PMP): ", cnt_test);
|
||||
|
||||
// check if PMP is implemented
|
||||
if (neorv32_cpu_csr_read(CSR_MZEXT) & (1<<CSR_MZEXT_PMP)) {
|
||||
if (neorv32_cpu_pmp_get_num_regions() != 0) {
|
||||
|
||||
// Test access to protected region
|
||||
// ---------------------------------------------
|
||||
|
@ -1571,6 +1484,25 @@ int main() {
|
|||
#endif
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// HPM reports
|
||||
// ----------------------------------------------------------
|
||||
neorv32_cpu_csr_write(CSR_MCOUNTINHIBIT, -1); // stop all counters
|
||||
neorv32_uart_printf("\n\nHPM results:\n");
|
||||
if (num_hpm_cnts_global == 0) {neorv32_uart_printf("no HPMs available\n"); }
|
||||
if (num_hpm_cnts_global > 0) {neorv32_uart_printf("# Retired compr. instructions: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER3)); }
|
||||
if (num_hpm_cnts_global > 1) {neorv32_uart_printf("# I-fetch wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER4)); }
|
||||
if (num_hpm_cnts_global > 2) {neorv32_uart_printf("# Load operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER5)); }
|
||||
if (num_hpm_cnts_global > 3) {neorv32_uart_printf("# Store operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER6)); }
|
||||
if (num_hpm_cnts_global > 4) {neorv32_uart_printf("# Load/store wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER7)); }
|
||||
if (num_hpm_cnts_global > 5) {neorv32_uart_printf("# Unconditional jumps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER8)); }
|
||||
if (num_hpm_cnts_global > 6) {neorv32_uart_printf("# Conditional branches (all): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER9)); }
|
||||
if (num_hpm_cnts_global > 7) {neorv32_uart_printf("# Conditional branches (taken): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER10)); }
|
||||
if (num_hpm_cnts_global > 8) {neorv32_uart_printf("# Entered traps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11)); }
|
||||
if (num_hpm_cnts_global > 9) {neorv32_uart_printf("# Illegal operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER12)); }
|
||||
neorv32_uart_printf("\n");
|
||||
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Final test reports
|
||||
// ----------------------------------------------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue