diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index fbc51eeb5..f9e176c85 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -460,10 +460,12 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa } } } - if (found != -1) + if (found != -1) { + target->current_target_name = target->rtos->thread_details[found].thread_name_str; gdb_put_packet(connection, "OK", 2); /* thread alive */ - else + } else { gdb_put_packet(connection, "E01", 3); /* thread not found */ + } return ERROR_OK; } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for * all other operations ) */ diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am index 328a317b1..c159cf197 100644 --- a/src/target/riscv/Makefile.am +++ b/src/target/riscv/Makefile.am @@ -15,6 +15,7 @@ noinst_LTLIBRARIES += %D%/libriscv.la %D%/riscv-011_reg.h \ %D%/riscv-013.h \ %D%/riscv-013_reg.h \ + %D%/nuclei_riscv.h \ %D%/batch.c \ %D%/program.c \ %D%/riscv-011.c \ @@ -25,6 +26,7 @@ noinst_LTLIBRARIES += %D%/libriscv.la %D%/riscv_reg.c \ %D%/riscv_semihosting.c \ %D%/debug_defines.c \ + %D%/nuclei_riscv.c \ %D%/debug_reg_printer.c STARTUP_TCL_SRCS += %D%/startup.tcl diff --git a/src/target/riscv/nuclei_riscv.c b/src/target/riscv/nuclei_riscv.c new file mode 100644 index 000000000..1d0944ebc --- /dev/null +++ b/src/target/riscv/nuclei_riscv.c @@ -0,0 +1,940 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2023 by Nuclei wangyanwen * + * wangyanwen@nucleisys.com * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target/target.h" +#include "target/target_type.h" +#include "helper/log.h" +#include "helper/fileio.h" +#include "helper/time_support.h" +#include "riscv.h" +#include "rtos/rtos.h" +#include "debug_defines.h" +#include + +#define KB (1024) +#define MB (KB * 1024) +#define GB (MB * 1024) +#define EXTENSION_NUM (26) +#define POWER_FOR_TWO(n) (1 << (n)) +#define LINESZ(n) ((n) > 0 ? POWER_FOR_TWO((n) - 1) : 0) +#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which) - 1))) + +#define show_safety_mechanism(safetyMode) do { \ + switch (safetyMode) { \ + case 0b00: \ + command_print_sameline(CMD, " No-Safety-Mechanism"); \ + break; \ + case 0b01: \ + command_print_sameline(CMD, " Lockstep"); \ + break; \ + case 0b10: \ + command_print_sameline(CMD, " Lockstep+SplitMode"); \ + break; \ + case 0b11: \ + command_print_sameline(CMD, " ASIL-B"); \ + break; \ + } \ +} while (0) + + +#define show_vpu_degree(degree) do { \ + switch (degree) { \ + case 0b00: \ + command_print_sameline(CMD, " DLEN=VLEN/2"); \ + break; \ + case 0b01: \ + command_print_sameline(CMD, " DLEN=VLEN"); \ + break; \ + } \ +} while (0) + +#define print_size(bytes) do { \ + if ((bytes) / GB) { \ + command_print_sameline(CMD, " %d GB", (int)((bytes) / GB)); \ + } else if ((bytes) / MB) { \ + command_print_sameline(CMD, " %d MB", (int)((bytes) / MB)); \ + } else if ((bytes) / KB) { \ + command_print_sameline(CMD, " %d KB", (int)((bytes) / KB)); \ + } else { \ + command_print_sameline(CMD, " %d Byte", (int)(bytes)); \ + } \ +} while (0) + +#define show_cache_info(set, way, lsize, ecc) do { \ + print_size((set) * (way) * (lsize)); \ + command_print_sameline(CMD, "(set=%d,", (int)(set)); \ + command_print_sameline(CMD, "way=%d,", (int)(way)); \ + command_print_sameline(CMD, "lsize=%d,", (int)(lsize)); \ + command_print(CMD, "ecc=%d)", !!(ecc)); \ +} while (0) + +COMMAND_HANDLER(handle_nuclei_cpuinfo) +{ + riscv_reg_t csr_mcfg = 0; + riscv_reg_t csr_micfg = 0; + riscv_reg_t csr_mdcfg = 0; + riscv_reg_t iregion_base = 0; + riscv_reg_t csr_marchid = 0; + riscv_reg_t csr_mimpid = 0; + riscv_reg_t csr_misa = 0; + riscv_reg_t csr_mirgb = 0; + riscv_reg_t csr_mfiocfg = 0; + riscv_reg_t csr_mppicfg = 0; + riscv_reg_t csr_mtlbcfg = 0; + + struct target *target = get_current_target(CMD_CTX); + + command_print(CMD, "-----Nuclei RISC-V CPU Configuration Information-----"); + + /* ID and version */ + if (riscv_reg_get(target, &csr_marchid, CSR_MARCHID + GDB_REGNO_CSR0) == ERROR_OK) + command_print(CMD, " MARCHID: %lx", csr_marchid); + if (riscv_reg_get(target, &csr_mimpid, CSR_MIMPID + GDB_REGNO_CSR0) == ERROR_OK) + command_print(CMD, " MIMPID: %lx", csr_mimpid); + + /* ISA */ + if (riscv_reg_get(target, &csr_misa, CSR_MISA + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " ISA:"); + if (riscv_xlen(target) == 32) + command_print_sameline(CMD, " RV32"); + else + command_print_sameline(CMD, " RV64"); + for (int i = 0; i < EXTENSION_NUM; i++) { + if (csr_misa & BIT(i)) { + if ('X' == ('A' + i)) + command_print_sameline(CMD, " NICE"); + else + command_print_sameline(CMD, " %c", 'A' + i); + } + } + if (riscv_reg_get(target, &csr_mcfg, CSR_MCFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + if (csr_mcfg & BIT(12)) + command_print_sameline(CMD, " Xxldspn1x"); + if (csr_mcfg & BIT(13)) + command_print_sameline(CMD, " Xxldspn2x"); + if (csr_mcfg & BIT(14)) + command_print_sameline(CMD, " Xxldspn3x"); + if (csr_mcfg & BIT(15)) + command_print_sameline(CMD, " Zc Xxlcz"); + if (csr_mcfg & BIT(19)) + command_print_sameline(CMD, " Smwg"); + } + command_print(CMD, " "); + } + + /* Support */ + if (riscv_reg_get(target, &csr_mcfg, CSR_MCFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " MCFG:"); + if (csr_mcfg & BIT(0)) + command_print_sameline(CMD, " TEE"); + if (csr_mcfg & BIT(1)) + command_print_sameline(CMD, " ECC"); + if (csr_mcfg & BIT(2)) + command_print_sameline(CMD, " ECLIC"); + if (csr_mcfg & BIT(3)) + command_print_sameline(CMD, " PLIC"); + if (csr_mcfg & BIT(4)) + command_print_sameline(CMD, " FIO"); + if (csr_mcfg & BIT(5)) + command_print_sameline(CMD, " PPI"); + if (csr_mcfg & BIT(6)) + command_print_sameline(CMD, " NICE"); + if (csr_mcfg & BIT(7)) + command_print_sameline(CMD, " ILM"); + if (csr_mcfg & BIT(8)) + command_print_sameline(CMD, " DLM"); + if (csr_mcfg & BIT(9)) + command_print_sameline(CMD, " ICACHE"); + if (csr_mcfg & BIT(10)) + command_print_sameline(CMD, " DCACHE"); + if (csr_mcfg & BIT(11)) + command_print_sameline(CMD, " SMP"); + if (csr_mcfg & BIT(12)) + command_print_sameline(CMD, " DSP_N1"); + if (csr_mcfg & BIT(13)) + command_print_sameline(CMD, " DSP_N2"); + if (csr_mcfg & BIT(14)) + command_print_sameline(CMD, " DSP_N3"); + if (csr_mcfg & BIT(15)) + command_print_sameline(CMD, " ZC_XLCZ_EXT"); + if (csr_mcfg & BIT(16)) + command_print_sameline(CMD, " IREGION"); + if (csr_mcfg & BIT(19)) + command_print_sameline(CMD, " SEC_MODE"); + if (csr_mcfg & BIT(20)) + command_print_sameline(CMD, " ETRACE"); + if (csr_mcfg & BIT(23)) + command_print_sameline(CMD, " VNICE"); + show_safety_mechanism(EXTRACT_FIELD(csr_mcfg, 0x3 << 21)); + show_vpu_degree(EXTRACT_FIELD(csr_mcfg, 0x3 << 17)); + command_print(CMD, " "); + } + + /* ILM */ + if (csr_mcfg & BIT(7)) { + if (riscv_reg_get(target, &csr_micfg, CSR_MICFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " ILM:"); + print_size(POWER_FOR_TWO(EXTRACT_FIELD(csr_micfg, 0x1F << 16) - 1) * 256); + if (csr_micfg & BIT(21)) + command_print_sameline(CMD, " execute-only"); + if (csr_micfg & BIT(22)) + command_print_sameline(CMD, " has-ecc"); + command_print(CMD, " "); + } + } + + /* DLM */ + if (csr_mcfg & BIT(8)) { + if (riscv_reg_get(target, &csr_mdcfg, CSR_MDCFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " DLM:"); + print_size(POWER_FOR_TWO(EXTRACT_FIELD(csr_mdcfg, 0x1F << 16) - 1) * 256); + if (csr_mdcfg & BIT(21)) + command_print_sameline(CMD, " has-ecc"); + command_print(CMD, " "); + } + } + + /* ICACHE */ + if (csr_mcfg & BIT(9)) { + if (riscv_reg_get(target, &csr_micfg, CSR_MICFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " ICACHE:"); + show_cache_info(POWER_FOR_TWO(EXTRACT_FIELD(csr_micfg, 0xF) + 3), + EXTRACT_FIELD(csr_micfg, 0x7 << 4) + 1, + POWER_FOR_TWO(EXTRACT_FIELD(csr_micfg, 0x7 << 7) + 2), + csr_mcfg & BIT(1)); + } + } + + /* DCACHE */ + if (csr_mcfg & BIT(10)) { + if (riscv_reg_get(target, &csr_mdcfg, CSR_MDCFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " DCACHE:"); + show_cache_info(POWER_FOR_TWO(EXTRACT_FIELD(csr_mdcfg, 0xF) + 3), + EXTRACT_FIELD(csr_mdcfg, 0x7 << 4) + 1, + POWER_FOR_TWO(EXTRACT_FIELD(csr_mdcfg, 0x7 << 7) + 2), + csr_mcfg & BIT(1)); + } + } + + /* TLB only present with MMU, when PLIC present MMU will present */ + if (csr_mcfg & BIT(3)) { + if (riscv_reg_get(target, &csr_mtlbcfg, CSR_MTLBCFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " TLB:"); + command_print(CMD, " MainTLB(set=%lu way=%lu entry=%lu ecc=%lu) ITLB(entry=%lu) DTLB(entry=%lu)", + POWER_FOR_TWO(EXTRACT_FIELD(csr_mtlbcfg, 0xF) + 3), + EXTRACT_FIELD(csr_mtlbcfg, 0x7 << 4) + 1, + LINESZ(EXTRACT_FIELD(csr_mtlbcfg, 0x7 << 7)), + EXTRACT_FIELD(csr_mtlbcfg, 0x1 << 10), + LINESZ(EXTRACT_FIELD(csr_mtlbcfg, 0x7 << 16)), + LINESZ(EXTRACT_FIELD(csr_mtlbcfg, 0x7 << 19))); + } + } + + /* IREGION */ + if (csr_mcfg & BIT(16)) { + if (riscv_reg_get(target, &csr_mirgb, CSR_MIRGB_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " IREGION:"); + iregion_base = csr_mirgb & (~0x3FF); + command_print_sameline(CMD, " %#lx", iregion_base); + print_size(POWER_FOR_TWO(EXTRACT_FIELD(csr_mirgb, 0x1F << 1) - 1) * KB); + command_print(CMD, " "); + command_print(CMD, " Unit Size Address"); + command_print(CMD, " INFO 64KB %#lx", iregion_base); + command_print(CMD, " DEBUG 64KB %#lx", iregion_base + 0x10000); + if (csr_mcfg & BIT(2)) + command_print(CMD, " ECLIC 64KB %#lx", iregion_base + 0x20000); + command_print(CMD, " TIMER 64KB %#lx", iregion_base + 0x30000); + if (csr_mcfg & BIT(11)) + command_print(CMD, " SMP&CC 64KB %#lx", iregion_base + 0x40000); + riscv_reg_t smp_cfg = 0; + target_read_memory(target, iregion_base + 0x40004, 4, 1, (uint8_t *)&smp_cfg); + if ((csr_mcfg & BIT(2)) && (EXTRACT_FIELD(smp_cfg, 0x1F << 1) >= 2)) + command_print(CMD, " CIDU 64KB %#lx", iregion_base + 0x50000); + if (csr_mcfg & BIT(3)) + command_print(CMD, " PLIC 64MB %#lx", iregion_base + 0x4000000); + /* SMP */ + if (csr_mcfg & BIT(11)) { + command_print_sameline(CMD, " SMP_CFG:"); + command_print_sameline(CMD, " CC_PRESENT=%ld", EXTRACT_FIELD(smp_cfg, 0x1)); + command_print_sameline(CMD, " SMP_CORE_NUM=%ld", EXTRACT_FIELD(smp_cfg, 0x3F << 1)); + command_print_sameline(CMD, " IOCP_NUM=%ld", EXTRACT_FIELD(smp_cfg, 0x3F << 7)); + command_print(CMD, " PMON_NUM=%ld", EXTRACT_FIELD(smp_cfg, 0x3F << 13)); + } + /* ECLIC */ + if (csr_mcfg & BIT(2)) { + riscv_reg_t clic_cfg = 0; + target_read_memory(target, iregion_base + 0x20000, 4, 1, (uint8_t *)&clic_cfg); + riscv_reg_t clic_info = 0; + target_read_memory(target, iregion_base + 0x20004, 4, 1, (uint8_t *)&clic_info); + riscv_reg_t clic_mth = 0; + target_read_memory(target, iregion_base + 0x20008, 4, 1, (uint8_t *)&clic_mth); + command_print_sameline(CMD, " ECLIC:"); + command_print_sameline(CMD, " VERSION=0x%x", EXTRACT_FIELD(clic_info, 0xFF << 13)); + command_print_sameline(CMD, " NUM_INTERRUPT=%x", EXTRACT_FIELD(clic_info, 0xFFF)); + command_print_sameline(CMD, " CLICINTCTLBITS=%x", EXTRACT_FIELD(clic_info, 0xF << 21)); + command_print_sameline(CMD, " MTH=%x", EXTRACT_FIELD(clic_mth, 0xFF << 24)); + command_print(CMD, " NLBITS=%x", EXTRACT_FIELD(clic_cfg, 0xF << 1)); + } + /* L2CACHE */ + if (smp_cfg & 0x1) { + command_print_sameline(CMD, " L2CACHE:"); + riscv_reg_t cc_cfg = 0; + target_read_memory(target, iregion_base + 0x40008, 4, 1, (uint8_t *)&cc_cfg); + show_cache_info(POWER_FOR_TWO(EXTRACT_FIELD(cc_cfg, 0xF)), EXTRACT_FIELD(cc_cfg, 0xF << 4) + 1, + POWER_FOR_TWO(EXTRACT_FIELD(cc_cfg, 0x7 << 8) + 2), cc_cfg & BIT(11)); + } + /* INFO */ + command_print(CMD, " INFO-Detail:"); + riscv_reg_t mpasize = 0; + target_read_memory(target, iregion_base, 4, 1, (uint8_t *)&mpasize); + command_print(CMD, " mpasize : %ld", mpasize); + riscv_reg_t cmo_info = 0; + target_read_memory(target, iregion_base + 4, 4, 1, (uint8_t *)&cmo_info); + if (cmo_info & 0x1) { + command_print(CMD, " cbozero : %dByte", + POWER_FOR_TWO(EXTRACT_FIELD(cmo_info, 0xF << 6) + 2)); + command_print(CMD, " cmo : %dByte", + POWER_FOR_TWO(EXTRACT_FIELD(cmo_info, 0xF << 2) + 2)); + if (cmo_info & 0x2) + command_print(CMD, " has_prefecth"); + } + riscv_reg_t mcppi_cfg_lo = 0; + target_read_memory(target, iregion_base + 0x80, 4, 1, (uint8_t *)&mcppi_cfg_lo); + riscv_reg_t mcppi_cfg_hi = 0; + target_read_memory(target, iregion_base + 0x84, 4, 1, (uint8_t *)&mcppi_cfg_hi); + if (mcppi_cfg_lo & 0x1) { + if (riscv_xlen(target) == 32) + command_print_sameline(CMD, " cppi : %#lx", mcppi_cfg_lo & (~0x3FF)); + else + command_print_sameline(CMD, " cppi : %#lx", + (mcppi_cfg_hi << 32) | (mcppi_cfg_lo & (~0x3FF))); + print_size(POWER_FOR_TWO(EXTRACT_FIELD(mcppi_cfg_lo, 0x1F << 1) - 1) * KB); + command_print(CMD, " "); + } + } + } + + /* TLB */ + if (csr_mcfg & BIT(3)) { + if (riscv_reg_get(target, &csr_mtlbcfg, CSR_MTLBCFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print(CMD, " DTLB: %ld entry", + POWER_FOR_TWO(EXTRACT_FIELD(csr_mtlbcfg, 0x7 << 19) - 1)); + command_print(CMD, " ITLB: %ld entry", + POWER_FOR_TWO(EXTRACT_FIELD(csr_mtlbcfg, 0x7 << 16) - 1)); + command_print_sameline(CMD, " MTLB:"); + command_print_sameline(CMD, " %ld entry", POWER_FOR_TWO(EXTRACT_FIELD(csr_mtlbcfg, 0xF) + 3) * + (EXTRACT_FIELD(csr_mtlbcfg, 0x7 << 4) + 1)); + if (csr_mtlbcfg & BIT(10)) + command_print_sameline(CMD, " has_ecc"); + command_print(CMD, " "); + } + } + + /* FIO */ + if (csr_mcfg & BIT(4)) { + if (riscv_reg_get(target, &csr_mfiocfg, CSR_MFIOCFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " FIO:"); + command_print_sameline(CMD, " %#lx", csr_mfiocfg & (~0x3FF)); + print_size(POWER_FOR_TWO(EXTRACT_FIELD(csr_mfiocfg, 0x1F << 1) - 1) * KB); + command_print(CMD, " "); + } + } + + /* PPI */ + if (csr_mcfg & BIT(5)) { + if (riscv_reg_get(target, &csr_mppicfg, CSR_MPPICFG_INFO + GDB_REGNO_CSR0) == ERROR_OK) { + command_print_sameline(CMD, " PPI:"); + command_print_sameline(CMD, " %#lx", csr_mppicfg & (~0x3FF)); + print_size(POWER_FOR_TWO(EXTRACT_FIELD(csr_mppicfg, 0x1F << 1) - 1) * KB); + command_print(CMD, " "); + } + } + + command_print(CMD, "----End of cpuinfo"); + return ERROR_OK; +} + +#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) +#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) +#define field_value(mask, val) set_field((riscv_reg_t)0, mask, val) + +#define ETRACE_BASE_HI (0x00) +#define ETRACE_BASE_LO (0x04) +#define ETRACE_WLEN (0x08) +#define ETRACE_ENA (0x0c) +#define ETRACE_INTERRUPT (0x10) +#define ETRACE_MAXTIME (0x14) +#define ETRACE_EARLY (0x18) +#define ETRACE_ATOVF (0x1c) +#define ETRACE_ENDOFFSET (0x20) +#define ETRACE_FLG (0x24) +#define ETRACE_ONGOING (0x28) +#define ETRACE_TIMEOUT (0x2c) +#define ETRACE_IDLE (0x30) +#define ETRACE_FIFO (0x34) +#define ETRACE_ATBDW (0x38) +#define ETRACE_WRAP (0x3c) +#define ETRACE_COMPACT (0x40) + +static target_addr_t atb2axi_config_addr = 0xa5a5a5a5; +static target_addr_t buffer_addr = 0xa5a5a5a5; +static uint32_t buffer_size; + +static int etrace_read_reg(struct target *target, uint32_t offset, uint32_t *value) +{ + if (atb2axi_config_addr == 0xa5a5a5a5) + return ERROR_OK; + int result = target_read_u32(target, atb2axi_config_addr + offset, value); + if (result != ERROR_OK) { + LOG_ERROR("%s error at %#x", __func__, atb2axi_config_addr + offset); + return result; + } + return ERROR_OK; +} + +static int etrace_write_reg(struct target *target, uint32_t offset, uint32_t value) +{ + if (atb2axi_config_addr == 0xa5a5a5a5) + return ERROR_OK; + int result = target_write_u32(target, atb2axi_config_addr + offset, value); + if (result != ERROR_OK) { + LOG_ERROR("%s error writing %#x to %#x", __func__, value, atb2axi_config_addr + offset); + return result; + } + return ERROR_OK; +} + +void etrace_stop(struct target *target) +{ + uint32_t tmp; + uint32_t wait_idle = 0x100; + + etrace_write_reg(target, ETRACE_ENA, 0); + do { + etrace_read_reg(target, ETRACE_IDLE, &tmp); + wait_idle -= 1; + if (wait_idle == 0) + break; + } while (tmp != 1); +} + +COMMAND_HANDLER(handle_etrace_config_command) +{ + uint32_t wrap; + + if (CMD_ARGC != 4) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + uint32_t tmp; + + etrace_read_reg(target, ETRACE_ENA, &tmp); + if (tmp) { + LOG_ERROR("etrace already start, please stop it first and then config."); + return 0; + } + + COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], atb2axi_config_addr); + COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], buffer_addr); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], buffer_size); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], wrap); + + etrace_write_reg(target, ETRACE_BASE_HI, (uint32_t)(buffer_addr >> 32)); + etrace_write_reg(target, ETRACE_BASE_LO, (uint32_t)buffer_addr); + etrace_write_reg(target, ETRACE_WLEN, buffer_size); + if (wrap) { + etrace_write_reg(target, ETRACE_WRAP, 1); + etrace_write_reg(target, ETRACE_COMPACT, 0); + } else { + etrace_write_reg(target, ETRACE_WRAP, 0); + etrace_write_reg(target, ETRACE_COMPACT, 1); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_etrace_enable_command) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + struct target *target_real; + if (target->smp) + target_real = get_target(target->current_target_name); + else + target_real = target; + + riscv_reg_t dpc_rb; + riscv_reg_t tselect = 0; + riscv_reg_t tdata1 = field_value(CSR_MCONTROL_TYPE(riscv_xlen(target_real)), CSR_TDATA1_TYPE_MCONTROL) | + field_value(CSR_MCONTROL_ACTION, CSR_MCONTROL_ACTION_TRACE_ON) | + field_value(CSR_MCONTROL_M, 1) | + field_value(CSR_MCONTROL_S, 1) | + field_value(CSR_MCONTROL_U, 1) | + field_value(CSR_MCONTROL_EXECUTE, 1); + if (riscv_reg_set(target_real, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + return ERROR_FAIL; + if (riscv_reg_set(target_real, GDB_REGNO_TDATA1, tdata1) != ERROR_OK) + return ERROR_FAIL; + if (riscv_reg_get(target_real, &dpc_rb, GDB_REGNO_DPC) != ERROR_OK) + return ERROR_FAIL; + if (riscv_reg_set(target_real, GDB_REGNO_TDATA2, dpc_rb) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_etrace_disable_command) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + struct target *target_real; + if (target->smp) + target_real = get_target(target->current_target_name); + else + target_real = target; + + riscv_reg_t dpc_rb; + riscv_reg_t tselect = 1; + riscv_reg_t tdata1 = field_value(CSR_MCONTROL_TYPE(riscv_xlen(target_real)), CSR_TDATA1_TYPE_MCONTROL) | + field_value(CSR_MCONTROL_ACTION, CSR_MCONTROL_ACTION_TRACE_OFF) | + field_value(CSR_MCONTROL_M, 1) | + field_value(CSR_MCONTROL_S, 1) | + field_value(CSR_MCONTROL_U, 1) | + field_value(CSR_MCONTROL_EXECUTE, 1); + if (riscv_reg_set(target_real, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + return ERROR_FAIL; + if (riscv_reg_set(target_real, GDB_REGNO_TDATA1, tdata1) != ERROR_OK) + return ERROR_FAIL; + if (riscv_reg_get(target_real, &dpc_rb, GDB_REGNO_DPC) != ERROR_OK) + return ERROR_FAIL; + if (riscv_reg_set(target_real, GDB_REGNO_TDATA2, dpc_rb) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_etrace_start_command) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + etrace_write_reg(target, ETRACE_ENA, 1); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_etrace_stop_command) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + etrace_stop(target); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_etrace_dump_command) +{ + uint32_t end_offset; + uint32_t full_flag; + target_addr_t address; + uint32_t size; + uint8_t *temp; + struct fileio *fileio; + int retval, retvaltemp; + struct duration bench; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + uint32_t tmp; + + etrace_read_reg(target, ETRACE_ENA, &tmp); + if (tmp) { + LOG_ERROR("etrace already start, please stop it first and then dump."); + return 0; + } + + etrace_read_reg(target, ETRACE_ENDOFFSET, &end_offset); + etrace_read_reg(target, ETRACE_FLG, &full_flag); + if (full_flag) { + address = buffer_addr + end_offset; + size = buffer_size; + } else { + address = buffer_addr; + size = end_offset; + } + + uint32_t temp_size = (size > 4096) ? 4096 : size; + temp = malloc(temp_size); + if (!temp) + return ERROR_FAIL; + + if (fileio_open(&fileio, CMD_ARGV[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + return ERROR_FAIL; + + duration_start(&bench); + + while (size > 0) { + size_t size_written; + uint32_t this_run_size = (size > temp_size) ? temp_size : size; + if ((this_run_size + address) > (buffer_addr + buffer_size)) + this_run_size = (buffer_addr + buffer_size) - address; + + retval = target_read_buffer(target, address, this_run_size, temp); + if (retval != ERROR_OK) + break; + + retval = fileio_write(fileio, this_run_size, temp, &size_written); + if (retval != ERROR_OK) + break; + + size -= this_run_size; + if ((this_run_size + address) == (buffer_addr + buffer_size)) + address = buffer_addr; + else + address += this_run_size; + } + + free(temp); + + if (retval == ERROR_OK && (duration_measure(&bench) == ERROR_OK)) { + size_t filesize; + retval = fileio_size(fileio, &filesize); + if (retval != ERROR_OK) + return retval; + command_print(CMD, + "dumped %zu bytes in %fs (%0.3f KiB/s)", filesize, + duration_elapsed(&bench), duration_kbps(&bench, filesize)); + } + + retvaltemp = fileio_close(fileio); + if (retvaltemp != ERROR_OK) + return retvaltemp; + + return retval; +} + +COMMAND_HANDLER(handle_etrace_clear_command) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + etrace_stop(target); + + etrace_write_reg(target, ETRACE_ENDOFFSET, 0); + etrace_write_reg(target, ETRACE_FLG, 0); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_etrace_info_command) +{ + uint32_t end_offset; + uint32_t full_flag; + + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + etrace_read_reg(target, ETRACE_ENDOFFSET, &end_offset); + etrace_read_reg(target, ETRACE_FLG, &full_flag); + + command_print(CMD, "ATB2AXI Addr: %#x", atb2axi_config_addr); + command_print(CMD, "Buffer Addr: %#lx", buffer_addr); + command_print(CMD, "Buffer Size: %#x", buffer_size); + command_print_sameline(CMD, "Buffer Status: "); + if (full_flag) + command_print(CMD, "used 100%% from %#lx [wraped]", buffer_addr + end_offset); + else + command_print(CMD, "used %d%% from %#lx to %#lx", (end_offset * 100) / buffer_size, \ + buffer_addr, buffer_addr + end_offset); + + return ERROR_OK; +} + +static const struct command_registration etrace_command_handlers[] = { + { + .name = "config", + .handler = handle_etrace_config_command, + .mode = COMMAND_EXEC, + .help = "Configuration etrace.", + .usage = "atb2axi-config-addr buffer-addr buffer-size wrap", + }, + { + .name = "enable", + .handler = handle_etrace_enable_command, + .mode = COMMAND_EXEC, + .help = "enable etrace", + .usage = "", + }, + { + .name = "disable", + .handler = handle_etrace_disable_command, + .mode = COMMAND_EXEC, + .help = "disable etrace", + .usage = "", + }, + { + .name = "start", + .handler = handle_etrace_start_command, + .mode = COMMAND_EXEC, + .help = "start etrace collection", + .usage = "", + }, + { + .name = "stop", + .handler = handle_etrace_stop_command, + .mode = COMMAND_EXEC, + .help = "stop etrace collection", + .usage = "", + }, + { + .name = "dump", + .handler = handle_etrace_dump_command, + .mode = COMMAND_EXEC, + .help = "dump etrace data", + .usage = "filename", + }, + { + .name = "clear", + .handler = handle_etrace_clear_command, + .mode = COMMAND_EXEC, + .help = "clear etrace data", + .usage = "", + }, + { + .name = "info", + .handler = handle_etrace_info_command, + .mode = COMMAND_EXEC, + .help = "display etrace info", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +uint64_t nuclei_get_dmcustom(struct target *target, uint32_t type, uint32_t hart_id, uint32_t index) +{ + uint64_t out_data; + uint32_t address, value; + RISCV_INFO(r); + if (!r) { + LOG_ERROR("riscv_info is NULL!"); + return ERROR_FAIL; + } + + if (r->dmi_write) { + address = 0x70; + value = (type << 28) | (hart_id << 8) | index; + if (r->dmi_write(target, address, value) != ERROR_OK) + return ERROR_FAIL; + } else { + LOG_ERROR("dmi_write is not implemented for this target."); + return ERROR_FAIL; + } + + if (r->dmi_read) { + address = 0x71; + if (r->dmi_read(target, &value, address) != ERROR_OK) + return ERROR_FAIL; + out_data = value; + address = 0x72; + if (r->dmi_read(target, &value, address) != ERROR_OK) + return ERROR_FAIL; + out_data |= value << 32; + } else { + LOG_ERROR("dmi_read is not implemented for this target."); + return ERROR_FAIL; + } + return out_data; +} + +COMMAND_HANDLER(nuclei_set_expose_cpu_core) +{ + if (CMD_ARGC == 0) { + LOG_ERROR("Command expects parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(info); + int ret = ERROR_OK; + + for (unsigned int i = 0; i < CMD_ARGC; i++) { + ret = parse_ranges(&info->expose_nuclei_cpu_core, CMD_ARGV[i], "nuclei_cpu_core", 0xFF); + if (ret != ERROR_OK) + break; + } + + return ret; +} + +COMMAND_HANDLER(nuclei_set_examine_cpu_core) +{ + if (CMD_ARGC == 0) { + LOG_ERROR("Command expects parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + uint64_t value; + uint32_t halt_id = 0; + uint32_t index = 0; + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + if (!r) { + LOG_ERROR("riscv_info is NULL!"); + return ERROR_FAIL; + } + + if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], halt_id); + range_list_t *entry; + list_for_each_entry(entry, &r->expose_nuclei_cpu_core, list) { + value = nuclei_get_dmcustom(target, 0, halt_id, entry->high); + command_print_sameline(CMD, "%u: ", entry->high); + command_print(CMD, "0x%016" PRIx64, value); + } + } else if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], halt_id); + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], index); + value = nuclei_get_dmcustom(target, 0, halt_id, index); + command_print_sameline(CMD, "%u: ", index); + command_print(CMD, "0x%016" PRIx64, value); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_halt_group_command) +{ + if (CMD_ARGC < 2) { + LOG_ERROR("Command expects parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + bool on_off; + COMMAND_PARSE_BOOL(CMD_ARGV[0], on_off, "on", "off"); + + struct target *target; + RISCV_INFO(r); + if (r->dmi_write) { + int retval = ERROR_OK; + for (int i = 1; i < CMD_ARGC; i++) { + target = get_target(CMD_ARGV[i]); + if (on_off) + retval = r->dmi_write(target, DM_DMCS2, 0x7); + else + retval = r->dmi_write(target, DM_DMCS2, 0x0); + } + return retval; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_resume_group_command) +{ + if (CMD_ARGC < 2) { + LOG_ERROR("Command expects parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + bool on_off; + COMMAND_PARSE_BOOL(CMD_ARGV[0], on_off, "on", "off"); + + struct target *target; + RISCV_INFO(r); + if (r->dmi_write) { + int retval = ERROR_OK; + for (int i = 1; i < CMD_ARGC; i++) { + target = get_target(CMD_ARGV[i]); + if (on_off) + retval = r->dmi_write(target, DM_DMCS2, 0x887); + else + retval = r->dmi_write(target, DM_DMCS2, 0x0); + } + return retval; + } + + return ERROR_OK; +} + +static const struct command_registration cti_command_handlers[] = { + { + .name = "halt_group", + .handler = handle_halt_group_command, + .mode = COMMAND_EXEC, + .help = "Configure and clear corss-trigger halt group", + .usage = "halt_group on/off target_name0 target_name1", + }, + { + .name = "resume_group", + .handler = handle_resume_group_command, + .mode = COMMAND_EXEC, + .help = "Configure and clear corss-trigger resume group", + .usage = "resume_group on/off target_name0 target_name1", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration nuclei_command_group_handlers[] = { + { + .name = "cpuinfo", + .handler = handle_nuclei_cpuinfo, + .mode = COMMAND_ANY, + .usage = "", + .help = "Displays some information about the target" + }, + { + .name = "etrace", + .mode = COMMAND_ANY, + .help = "Embedded Trace command group", + .usage = "", + .chain = etrace_command_handlers, + }, + { + .name = "expose_cpu_core", + .handler = nuclei_set_expose_cpu_core, + .mode = COMMAND_CONFIG, + .usage = " ... ", + .help = "Configure a list of index for `nuclei_examine_cpu_core` to expose in " + "This must be executed before `init`." + }, + { + .name = "examine_cpu_core", + .handler = nuclei_set_examine_cpu_core, + .mode = COMMAND_ANY, + .usage = " [index]", + .help = "Return the 64-bit value read from dm-custom1 and dm-custom2 " + "value = dm-custom2 << 32 + dm-custom1 " + }, + { + .name = "cti", + .mode = COMMAND_ANY, + .help = "Cross trigger command group", + .usage = "", + .chain = cti_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/riscv/nuclei_riscv.h b/src/target/riscv/nuclei_riscv.h new file mode 100644 index 000000000..7c1e293e0 --- /dev/null +++ b/src/target/riscv/nuclei_riscv.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2023 by Nuclei wangyanwen * + * wangyanwen@nucleisys.com * + ***************************************************************************/ + +#ifndef TARGET__RISCV__NUCLEI_RISCV_H +#define TARGET__RISCV__NUCLEI_RISCV_H + +extern const struct command_registration nuclei_command_group_handlers[]; + +#endif /* TARGET__RISCV__NUCLEI_RISCV_H */ diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 069473c9a..5d9264cdf 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1871,6 +1871,7 @@ static int examine_dm(struct target *target) /* Before doing anything else we must first enumerate the harts. */ const int max_hart_count = MIN(RISCV_MAX_HARTS, hartsel + 1); + uint64_t value; if (dm->hart_count < 0) { for (int i = 0; i < max_hart_count; ++i) { /* TODO: This is extremely similar to @@ -1904,6 +1905,13 @@ static int examine_dm(struct target *target) if (result != ERROR_OK) return result; } + + value = nuclei_get_dmcustom(target, 0, i, 0); + LOG_INFO("coreid=%d, 00 : 0x%lx", i, value); + value = nuclei_get_dmcustom(target, 0, i, 16); + LOG_INFO("coreid=%d, 16 : 0x%lx", i, value); + value = nuclei_get_dmcustom(target, 0, i, 32); + LOG_INFO("coreid=%d, 32 : 0x%lx", i, value); } LOG_TARGET_DEBUG(target, "Detected %d harts.", dm->hart_count); } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 0ca921657..fab2128e3 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -27,6 +27,7 @@ #include "debug_defines.h" #include #include "field_helpers.h" +#include "nuclei_riscv.h" /*** JTAG registers. ***/ @@ -570,6 +571,10 @@ static void riscv_deinit_target(struct target *target) free(entry->name); free(entry); } + list_for_each_entry_safe(entry, tmp, &info->expose_nuclei_cpu_core, list) { + free(entry->name); + free(entry); + } free(target->arch_info); @@ -4150,7 +4155,6 @@ COMMAND_HANDLER(riscv_set_mem_access) return ERROR_OK; } - static bool parse_csr_address(const char *reg_address_str, unsigned int *reg_addr) { *reg_addr = -1; @@ -5631,6 +5635,13 @@ static const struct command_registration riscv_command_handlers[] = { .usage = "", .chain = semihosting_common_handlers }, + { + .name = "nuclei", + .mode = COMMAND_ANY, + .help = "Nuclei Command Group", + .usage = "", + .chain = nuclei_command_group_handlers + }, { .chain = smp_command_handlers }, @@ -5730,6 +5741,7 @@ static void riscv_info_init(struct target *target, struct riscv_info *r) INIT_LIST_HEAD(&r->expose_csr); INIT_LIST_HEAD(&r->expose_custom); INIT_LIST_HEAD(&r->hide_csr); + INIT_LIST_HEAD(&r->expose_nuclei_cpu_core); r->vsew64_supported = YNM_MAYBE; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 482d0fd71..2a786a5d7 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -347,6 +347,7 @@ struct riscv_info { /* The list of registers to mark as "hidden". Hidden registers are available * but do not appear in gdb targets description or reg command output. */ struct list_head hide_csr; + struct list_head expose_nuclei_cpu_core; riscv_sample_config_t sample_config; struct riscv_sample_buf sample_buf; diff --git a/src/target/target.h b/src/target/target.h index 7f1bc6e4b..654c5af01 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -121,6 +121,7 @@ struct target { char *cmd_name; /* tcl Name of target */ struct jtag_tap *tap; /* where on the jtag chain is this */ int32_t coreid; /* which device on the TAP? */ + char *current_target_name; /** Should we defer examine to later */ bool defer_examine; diff --git a/tcl/cpu/nuclei/cpuinfo.tcl b/tcl/cpu/nuclei/cpuinfo.tcl new file mode 100644 index 000000000..db69983a3 --- /dev/null +++ b/tcl/cpu/nuclei/cpuinfo.tcl @@ -0,0 +1,376 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +proc get_register {reg} { + set reg_info [get_reg $reg] + return [lindex $reg_info 1] +} + +proc get_memory {addr} { + return [read_memory $addr 32 1] +} + +proc extract_field {val which} { + set part_a [expr $val&$which] + set part_b [expr $which&[expr ~[expr $which-1]]] + return [expr $part_a/$part_b] +} + +proc pow_of_two {n} { + return [expr 1<<$n] +} + +proc linesz {n} { + switch $n { + "0" { + return 0 + } + default { + pow_of_two [expr $n-1] + } + } +} + +proc show_safety_mechanism {safetyMode} { + switch $safetyMode { + "0" { + puts -nonewline " No-Safety-Mechanism" + } + "1" { + puts -nonewline " Lockstep" + } + "2" { + puts -nonewline " Lockstep+SplitMode" + } + "3" { + puts -nonewline " ASIL-B" + } + } +} + +proc show_vpu_degree {degree} { + switch $degree { + "0" { + puts -nonewline " DLEN=VLEN/2" + } + "1" { + puts -nonewline " DLEN=VLEN" + } + } +} + +proc format_display {bytes} { + if [expr $bytes/[expr 1024*1024*1024]] { + puts -nonewline [format " %dGB" [expr $bytes/[expr 1024*1024*1024]]] + } elseif [expr $bytes/[expr 1024*1024]] { + puts -nonewline [format " %dMB" [expr $bytes/[expr 1024*1024]]] + } elseif [expr $bytes/[expr 1024]] { + puts -nonewline [format " %dKB" [expr $bytes/[expr 1024]]] + } else { + puts -nonewline [format " %dByte" $bytes] + } +} + +proc show_cache_info {set way lsize ecc} { + format_display [expr $set*$way*$lsize] + puts -nonewline [format "(set=%d," $set] + puts -nonewline [format "way=%d," $way] + puts -nonewline [format "lsize=%d," $lsize] + puts -nonewline [format "ecc=%d)" [expr !!$ecc]] +} + +proc nuclei_cpuinfo {} { + + set riscv_info [riscv info] + dict for {key value} $riscv_info { + if {$key == "hart.xlen"} { + set xlen $value + } + } + + puts "-----Nuclei RISC-V CPU Configuration Information-----" + + set marchid [get_register marchid] + if {$marchid != 0} { + puts [format " MARCHID: %lx" $marchid] + } + + set mimpid [get_register mimpid] + if {$mimpid != 0} { + puts [format " MIMPID: %lx" $mimpid] + } + + set misa [get_register misa] + if {$misa != 0} { + puts -nonewline " ISA:" + if {$xlen == 32} { + puts -nonewline " RV32" + } else { + puts -nonewline " RV64" + } + for {set i 0} {$i < 26} {incr i} { + if [expr 1&[expr $misa>>$i]] { + if {88 == [expr 65+$i]} { + puts -nonewline " NICE" + } else { + puts -nonewline [format " %c" [expr 65+$i]] + } + } + } + } + + set mcfg_info [get_register mcfg_info] + if [expr $mcfg_info&[expr 1<<12]] { + puts -nonewline " Xxldspn1x" + } + if [expr $mcfg_info&[expr 1<<13]] { + puts -nonewline " Xxldspn2x" + } + if [expr $mcfg_info&[expr 1<<14]] { + puts -nonewline " Xxldspn3x" + } + if [expr $mcfg_info&[expr 1<<15]] { + puts -nonewline " Zc Xxlcz" + } + if [expr $mcfg_info&[expr 1<<19]] { + puts -nonewline " Smwg" + } + puts "" + + if {$mcfg_info != 0} { + puts -nonewline " MCFG:" + if [expr $mcfg_info&[expr 1<<0]] { + puts -nonewline " TEE" + } + if [expr $mcfg_info&[expr 1<<1]] { + puts -nonewline " ECC" + } + if [expr $mcfg_info&[expr 1<<2]] { + puts -nonewline " ECLIC" + } + if [expr $mcfg_info&[expr 1<<3]] { + puts -nonewline " PLIC" + } + if [expr $mcfg_info&[expr 1<<4]] { + puts -nonewline " FIO" + } + if [expr $mcfg_info&[expr 1<<5]] { + puts -nonewline " PPI" + } + if [expr $mcfg_info&[expr 1<<6]] { + puts -nonewline " NICE" + } + if [expr $mcfg_info&[expr 1<<7]] { + puts -nonewline " ILM" + } + if [expr $mcfg_info&[expr 1<<8]] { + puts -nonewline " DLM" + } + if [expr $mcfg_info&[expr 1<<9]] { + puts -nonewline " ICACHE" + } + if [expr $mcfg_info&[expr 1<<10]] { + puts -nonewline " DCACHE" + } + if [expr $mcfg_info&[expr 1<<11]] { + puts -nonewline " SMP" + } + if [expr $mcfg_info&[expr 1<<12]] { + puts -nonewline " DSP-N1" + } + if [expr $mcfg_info&[expr 1<<13]] { + puts -nonewline " DSP-N2" + } + if [expr $mcfg_info&[expr 1<<14]] { + puts -nonewline " DSP-N3" + } + if [expr $mcfg_info&[expr 1<<15]] { + puts -nonewline " ZC_XLCZ_EXT" + } + if [expr $mcfg_info&[expr 1<<16]] { + puts -nonewline " IREGION" + } + if [expr $mcfg_info&[expr 1<<19]] { + puts -nonewline " SEC_MODE" + } + if [expr $mcfg_info&[expr 1<<20]] { + puts -nonewline " ETRACE" + } + if [expr $mcfg_info&[expr 1<<23]] { + puts -nonewline " VNICE" + } + show_safety_mechanism [extract_field $mcfg_info [expr 0x3<<21]] + show_vpu_degree [extract_field $mcfg_info [expr 0x3<<17]] + puts "" + + if [expr $mcfg_info&[expr 1<<7]] { + set micfg_info [get_register micfg_info] + if {$micfg_info != 0} { + puts -nonewline " ILM:" + format_display [expr [pow_of_two [expr [extract_field $micfg_info [expr 0x1F<<16]]-1]]*256] + if [expr $micfg_info&[expr 1<<21]] { + puts -nonewline " execute-only" + } + if [expr $micfg_info&[expr 1<<22]] { + puts -nonewline " has-ecc" + } + puts "" + } + } + + if [expr $mcfg_info&[expr 1<<8]] { + set mdcfg_info [get_register mdcfg_info] + if {$mdcfg_info != 0} { + puts -nonewline " DLM:" + format_display [expr [pow_of_two [expr [extract_field $mdcfg_info [expr 0x1F<<16]]-1]]*256] + if [expr $mdcfg_info&[expr 1<<21]] { + puts -nonewline " has-ecc" + } + puts "" + } + } + + if [expr $mcfg_info&[expr 1<<9]] { + set micfg_info [get_register micfg_info] + if {$micfg_info != 0} { + puts -nonewline " ICACHE:" + show_cache_info [pow_of_two [expr [extract_field $micfg_info 0xF]+3]] \ + [expr [extract_field $micfg_info [expr 7<<4]]+1] \ + [pow_of_two [expr [extract_field $micfg_info [expr 7<<7]]+2]] \ + [extract_field $mcfg_info [expr 0x1<<1]] + puts "" + } + } + + if [expr $mcfg_info&[expr 1<<10]] { + set mdcfg_info [get_register mdcfg_info] + if {$mdcfg_info != 0} { + puts -nonewline " DCACHE:" + show_cache_info [pow_of_two [expr [extract_field $mdcfg_info 15]+3]] \ + [expr [extract_field $mdcfg_info [expr 7<<4]]+1] \ + [pow_of_two [expr [extract_field $mdcfg_info [expr 7<<7]]+2]] \ + [extract_field $mcfg_info [expr 0x1<<1]] + puts "" + } + } + + if [expr $mcfg_info&[expr 1<<3]] { + set mtlbcfg_info [get_register mtlbcfg_info] + puts -nonewline " TLB:" + puts -nonewline [format " MainTLB(set=%lu" [pow_of_two [expr [extract_field $mtlbcfg_info 0xF]+3]]] + puts -nonewline [format " way=%lu" [expr [extract_field $mtlbcfg_info [expr 0x7<<4]]+1]] + puts -nonewline [format " entry=%lu" [linesz [extract_field $mtlbcfg_info [expr 0x7<<7]]]] + puts -nonewline [format " ecc=%lu)" [extract_field $mtlbcfg_info [expr 0x1<<10]]] + puts -nonewline [format " ITLB(entry=%lu)" [linesz [extract_field $mtlbcfg_info [expr 0x7<<16]]]] + puts -nonewline [format " DTLB(entry=%lu)" [linesz [extract_field $mtlbcfg_info [expr 0x7<<19]]]] + puts "" + } + + if [expr $mcfg_info&[expr 1<<16]] { + set mirgb_info [get_register mirgb_info] + puts -nonewline " IREGION:" + set iregion_base [expr $mirgb_info&[expr ~0x3FF]] + puts -nonewline [format " 0x%lx" $iregion_base] + format_display [expr [pow_of_two [expr [extract_field $mirgb_info [expr 0x1F<<1]]-1]]*1024] + puts "" + puts " Unit Size Address" + puts [format " INFO 64KB 0x%lx" $iregion_base] + puts [format " DEBUG 64KB 0x%lx" [expr $iregion_base+0x10000]] + if [expr $mcfg_info&[expr 1<<2]] { + puts [format " ECLIC 64KB 0x%lx" [expr $iregion_base+0x20000]] + } + puts [format " TIMER 64KB 0x%lx" [expr $iregion_base+0x30000]] + if [expr $mcfg_info&[expr 1<<11]] { + puts [format " SMP 64KB 0x%lx" [expr $iregion_base+0x40000]] + } + set smp_cfg [get_memory [expr $iregion_base+0x40004]] + if [expr $mcfg_info&[expr 1<<2]] { + if {[extract_field $smp_cfg [expr 31<<1]] >= 2} { + puts [format " CIDU 64KB 0x%lx" [expr $iregion_base+0x50000]] + } + } + if [expr $mcfg_info&[expr 1<<3]] { + puts [format " PLIC 64MB 0x%lx" [expr $iregion_base+0x4000000]] + } + + if [expr $mcfg_info&[expr 1<<11]] { + puts -nonewline " SMP_CFG:" + puts -nonewline [format " CC_PRESENT=%ld" [extract_field $smp_cfg 0x1]] + puts -nonewline [format " SMP_CORE_NUM=%ld" [extract_field $smp_cfg [expr 0x3F<<1]]] + puts -nonewline [format " IOCP_NUM=%ld" [extract_field $smp_cfg [expr 0x3F<<7]]] + puts [format " PMON_NUM=%ld" [extract_field $smp_cfg [expr 0x3F<<13]]] + } + + if [expr $mcfg_info&[expr 1<<2]] { + set clic_base [expr $iregion_base+0x20000] + set clic_cfg [expr $clic_base+0x0] + set clic_info [expr $clic_base+0x4] + set clic_mth [expr $clic_base+0x8] + set clic_cfg_value [get_memory $clic_cfg] + set clic_info_value [get_memory $clic_info] + set clic_mth_value [get_memory $clic_mth] + puts -nonewline " ECLIC:" + puts -nonewline [format " VERSION=0x%x" [extract_field $clic_info_value [expr 0xFF<<13]]] + puts -nonewline [format " NUM_INTERRUPT=%x" [extract_field $clic_info_value [expr 0xFFF<<0]]] + puts -nonewline [format " CLICINTCTLBITS=%x" [extract_field $clic_info_value [expr 0xF<<21]]] + puts -nonewline [format " MTH=%x" [extract_field $clic_mth_value [expr 0xFF<<24]]] + puts [format " NLBITS=%x" [extract_field $clic_cfg_value [expr 0xF<<1]]] + } + + if [expr $smp_cfg&1] { + puts -nonewline " L2CACHE:" + set cc_cfg [get_memory [expr $iregion_base+0x40008]] + show_cache_info [pow_of_two [extract_field $cc_cfg 0xF]] \ + [expr [extract_field $cc_cfg [expr 0xF<<4]]+1] \ + [pow_of_two [expr [extract_field $cc_cfg [expr 0x7<<8]]+2]] \ + [extract_field $cc_cfg [expr 0x1<<11]] + puts "" + } + + puts " INFO-Detail:" + set mpasize [get_memory $iregion_base] + puts [format " mpasize : %ld" $mpasize] + set cmo_info [get_memory [expr $iregion_base+4]] + if [expr $cmo_info&1] { + puts [format " cbozero : %dByte" \ + [pow_of_two [expr [extract_field $cmo_info [expr 0xF<<6]]+2]]] + puts [format " cmo : %dByte" \ + [pow_of_two [expr [extract_field $cmo_info [expr 0xF<<2]]+2]]] + if [expr $cmo_info&2] { + puts " has_prefecth" + } + } + set mcppi_cfg_lo [get_memory [expr $iregion_base+0x80]] + set mcppi_cfg_hi [get_memory [expr $iregion_base+0x84]] + if [expr $mcppi_cfg_lo&1] { + if {$xlen == 32} { + puts -nonewline [format " cppi : 0x%lx" \ + [expr $mcppi_cfg_lo&[expr ~0x3FF]]] + } else { + puts -nonewline [format " cppi : 0x%lx" \ + [expr [expr $mcppi_cfg_hi<<32]|[expr $mcppi_cfg_lo&[expr ~0x3FF]]]] + } + format_display [expr [pow_of_two [expr [extract_field $mcppi_cfg_lo [expr 0x1F<<1]-1]]]*1024] + puts " " + } + puts "" + } + + if [expr $mcfg_info&[expr 1<<4]] { + set mfiocfg_info [get_register mfiocfg_info] + puts -nonewline " FIO:" + puts -nonewline [format " 0x%lx" [expr $mfiocfg_info&[expr ~0x3FF]]] + format_display [expr [pow_of_two [expr [extract_field $mfiocfg_info [expr 0x1F<<1]]-1]]*1024] + puts "" + } + + if [expr $mcfg_info&[expr 1<<5]] { + set mppicfg_info [get_register mppicfg_info] + puts -nonewline " PPI:" + puts -nonewline [format " 0x%lx" [expr $mppicfg_info&[expr ~0x3FF]]] + format_display [expr [pow_of_two [expr [extract_field $mppicfg_info [expr 0x1F<<1]]-1]]*1024] + puts "" + } + } + + puts "----End of cpuinfo-----" +}