Compare commits

..

11 Commits

Author SHA1 Message Date
Dr-Noob
8ce24150e7 Add IME 2025-10-29 22:44:22 +01:00
Dr-Noob
a0cb54dc8b Add IME 2025-10-29 22:43:50 +01:00
Dr-Noob
8e6b0b1a2b Crazy amount of new extensions! 2025-10-29 22:39:22 +01:00
Dr-Noob
5bddbc6b06 [v1.06] Reorganize attributes in printer
This follows the same approach of gpufetch (in
6589de971750b7f4e52c0c35c031fe6204cefdba) where, instead of having a
separate struct for long and short names, both gets merged in a single
struct (ATTRIBUTE_INFO)

This indirectly fixes a bug in RISC-V printer where, if the output
was too large and the short name was selected, it could try to print
an out-of-bound value when accessing the ATTRIBUTE_PEAK. The reason is
that the long and short structures didnt have the same length (because
one attribute name was missing in the short struct). This is now fixed
since we have combined both long and short attribute names.

commit 6e8cccde32
Author: Dr-Noob <peibolms@gmail.com>
Date:   Wed Oct 29 21:54:38 2025 +0100

    Reorganize attributes in printer
2025-10-29 22:08:44 +01:00
Dr-Noob
a0c08ccc0b [v1.06][RISCV] Add support for SpacemiT K1-X SoC (#286) 2024-10-10 08:39:24 +01:00
Dr-Noob
65c75eb443 [v1.06][RISCV] Support for fetching mvendorid, marchid and mimpid (#286)
Getting these 3 RISC-V cpuinfo fields allows the detection of
microarchitecture (and other information), extending the RISC-V
detection capabilities. In particular, this is used here to detect
the marchid of Spacemit X60 uarch.

This commit also changes how the microarchitecture is fetched
(i.e., get_uarch) so that it does not rely only in the uarch field
in cpuinfo, but also on the marchid value.
2024-10-10 08:37:12 +01:00
Dr-Noob
2df8aa8217 [v1.06][X86] Warn the users whenever they use a VM (#293) 2024-10-09 08:52:47 +01:00
Dr-Noob
a5d52b59df [v1.06] Nit: Fix warning due to missing newline at the end of file 2024-10-09 08:29:51 +01:00
Dr-Noob
f09454d442 [v1.06][X86] Fix CPUID 000806EC clash (#298) 2024-10-07 08:30:30 +01:00
Dr-Noob
01406778be [v1.06][ARM] Add new Dimensity MTK SoCs (#288) 2024-09-22 22:13:50 +01:00
Dr-Noob
7d786ca1b7 [v1.06][ARM] Implement automatic SoC inferring from device tree
This is a major change in the SoC detection methodology.

Previous to this commit, the SoC (model, vendor and manufacturing
process) would only appear if the exact model was found in the LUT.
In other words, every supported SoC must be added manually to the LUT.
This would allow to show the precise SoC model and the manufacturing
process, which can only be hardcoded (i.e., it cannot be dynamically
determined).

This commit introduces guess_raw_soc_from_devtree, a new way of
inferring the SoC. This simply reads from the compatible file in the
device tree and tries to find a matching vendor to that string. If
there is a match, then we simply copy the model also from the
compatible string and show it directly.

This new implementation will show a less "precise" SoC name and
no manufacturing process because there would be no hardcoded value for
that SoC. However, it improves the scalability of the SoC detection
significantly because there is no longer a need to hardcode every
single SoC.

Lastly, there are some SoC vendors intentionally left outside the
scope of this function: For now I prefer to keep updating manually
the LUT for those to ensure the highest quality detection (e.g.,
showing precise SoC name and manufacturing process).
2024-09-22 17:11:31 +01:00
18 changed files with 524 additions and 140 deletions

View File

@@ -306,7 +306,21 @@ bool match_mediatek(char* soc_name, struct system_on_chip* soc) {
soc->vendor = SOC_VENDOR_MEDIATEK;
SOC_START
// Dimensity //
// TODO
// Dimensity 6000 Series //
// Dimensity 7000 Series //
// Dimensity 8000 Series //
// END TODO
// Dimensity 9000 Series //
SOC_EQ(tmp, "MT6983Z", "Dimensity 9000", SOC_MTK_MT6983Z, soc, 4)
SOC_EQ(tmp, "MT8798Z/C","Dimensity 9000", SOC_MTK_MT8798ZC, soc, 4)
SOC_EQ(tmp, "MT6983W", "Dimensity 9000+", SOC_MTK_MT6983W, soc, 4)
SOC_EQ(tmp, "MT8798Z/T","Dimensity 9000+", SOC_MTK_MT8798ZT, soc, 4)
SOC_EQ(tmp, "MT6985W", "Dimensity 9200+", SOC_MTK_MT6985W, soc, 4)
SOC_EQ(tmp, "MT6985", "Dimensity 9200", SOC_MTK_MT6985, soc, 4)
SOC_EQ(tmp, "MT6989", "Dimensity 9300", SOC_MTK_MT6989, soc, 4)
SOC_EQ(tmp, "MT8796", "Dimensity 9300", SOC_MTK_MT8796, soc, 4)
// Dimensity 1000 //
SOC_EQ(tmp, "MT6893Z", "Dimensity 1300", SOC_MTK_MT6893Z, soc, 6)
SOC_EQ(tmp, "MT6893", "Dimensity 1200", SOC_MTK_MT6893, soc, 6)
SOC_EQ(tmp, "MT6891", "Dimensity 1100", SOC_MTK_MT6891, soc, 6)
@@ -316,12 +330,21 @@ bool match_mediatek(char* soc_name, struct system_on_chip* soc) {
SOC_EQ(tmp, "MT6885Z", "Dimensity 1000L", SOC_MTK_MT6885Z, soc, 7)
SOC_EQ(tmp, "MT6889Z", "Dimensity 1000+", SOC_MTK_MT6889Z, soc, 7)
SOC_EQ(tmp, "MT6883Z", "Dimensity 1000C", SOC_MTK_MT6883Z, soc, 7)
SOC_EQ(tmp, "MT6833", "Dimensity 700", SOC_MTK_MT6833, soc, 7)
SOC_EQ(tmp, "MT6853", "Dimensity 720", SOC_MTK_MT6853, soc, 7)
// Dimensity 900
SOC_EQ(tmp, "MT6877V/Z","Dimensity 900", SOC_MTK_MT6877VZ, soc, 6)
SOC_EQ(tmp, "MT6877T" ,"Dimensity 920", SOC_MTK_MT6877T, soc, 6)
SOC_EQ(tmp, "MT6855" ,"Dimensity 930", SOC_MTK_MT6855, soc, 6)
// Dimensity 800
SOC_EQ(tmp, "MT6873", "Dimensity 800", SOC_MTK_MT6873, soc, 7)
SOC_EQ(tmp, "MT6853V", "Dimensity 800U", SOC_MTK_MT6853V, soc, 7)
SOC_EQ(tmp, "MT6833", "Dimensity 810", SOC_MTK_MT6833, soc, 6)
SOC_EQ(tmp, "MT6853V/T","Dimensity 800U", SOC_MTK_MT6853VT, soc, 7)
SOC_EQ(tmp, "MT6853T", "Dimensity 800U", SOC_MTK_MT6853T, soc, 7)
SOC_EQ(tmp, "MT6833P", "Dimensity 810", SOC_MTK_MT6833P, soc, 6)
SOC_EQ(tmp, "MT6833GP", "Dimensity 810", SOC_MTK_MT6833GP, soc, 6)
SOC_EQ(tmp, "MT6833V", "Dimensity 810", SOC_MTK_MT6833V, soc, 6)
SOC_EQ(tmp, "MT6875", "Dimensity 820", SOC_MTK_MT6875, soc, 7)
// Dimensity 700
SOC_EQ(tmp, "MT6833", "Dimensity 700", SOC_MTK_MT6833, soc, 7)
SOC_EQ(tmp, "MT6853V", "Dimensity 720", SOC_MTK_MT6853, soc, 7)
// Helio //
SOC_EQ(tmp, "MT6761D", "Helio A20", SOC_MTK_MT6761D, soc, 12)
SOC_EQ(tmp, "MT6761", "Helio A22", SOC_MTK_MT6761, soc, 12)
@@ -1091,6 +1114,8 @@ struct system_on_chip* guess_raw_soc_from_devtree(struct system_on_chip* soc) {
for (int i=0; i < num_vendors; i++) {
if (strcmp(socFromDevtree[index].compatible, dt_vendors[i]->vendor) == 0) {
fill_soc_raw(soc, dt_vendors[i]->model, socFromDevtree[index].soc_vendor);
printWarn("Your SoC is unsupported by cpufetch but could still be detected successfully. If you want to help improve the project, please paste the output of 'cpufetch --verbose' on https://github.com/Dr-Noob/cpufetch/issues");
return soc;
}
}
index++;
@@ -1357,9 +1382,9 @@ struct system_on_chip* get_soc(struct cpuInfo* cpu) {
soc->model = SOC_MODEL_UNKNOWN;
soc->process = UNKNOWN;
#else
if(soc->model == SOC_MODEL_UNKNOWN) {
// raw_name might not be NULL, but if we were unable to find
// the exact SoC, just print "Unkwnown"
if(soc->raw_name == NULL) {
// We were unable to find the SoC, so just initialize raw_name
// with the unknown string
soc->raw_name = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
snprintf(soc->raw_name, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
}

View File

@@ -192,6 +192,22 @@ enum {
SOC_MTK_MT9950,
SOC_MTK_MT9972,
SOC_MTK_MT9982,
SOC_MTK_MT6983Z,
SOC_MTK_MT8798ZC,
SOC_MTK_MT6983W,
SOC_MTK_MT8798ZT,
SOC_MTK_MT6985W,
SOC_MTK_MT6985,
SOC_MTK_MT6989,
SOC_MTK_MT8796,
SOC_MTK_MT6877VZ,
SOC_MTK_MT6877T,
SOC_MTK_MT6855,
SOC_MTK_MT6853VT,
SOC_MTK_MT6853T,
SOC_MTK_MT6833P,
SOC_MTK_MT6833GP,
SOC_MTK_MT6833V,
// Snapdragon //
SOC_SNAPD_QSD8650,
SOC_SNAPD_QSD8250,
@@ -427,7 +443,7 @@ inline static VENDOR get_soc_vendor_from_soc(SOC soc) {
else if(soc >= SOC_HISILICON_3620 && soc <= SOC_HISILICON_9000S) return SOC_VENDOR_KIRIN;
else if(soc >= SOC_KUNPENG_920 && soc <= SOC_KUNPENG_930) return SOC_VENDOR_KUNPENG;
else if(soc >= SOC_EXYNOS_3475 && soc <= SOC_EXYNOS_880) return SOC_VENDOR_EXYNOS;
else if(soc >= SOC_MTK_MT6893 && soc <= SOC_MTK_MT8783) return SOC_VENDOR_MEDIATEK;
else if(soc >= SOC_MTK_MT5327 && soc <= SOC_MTK_MT6833V) return SOC_VENDOR_MEDIATEK;
else if(soc >= SOC_SNAPD_QSD8650 && soc <= SOC_SNAPD_SC8280XP) return SOC_VENDOR_SNAPDRAGON;
else if(soc >= SOC_APPLE_M1 && soc <= SOC_APPLE_M3_MAX) return SOC_VENDOR_APPLE;
else if(soc >= SOC_ALLWINNER_A10 && soc <= SOC_ALLWINNER_R328) return SOC_VENDOR_ALLWINNER;

View File

@@ -445,6 +445,26 @@ $C1 .######### |__________|###### |__________| \
$C1 ########### ___########### __________ \
$C1.########## |__________| |__________| "
#define ASCII_SPACEMIT \
"$C1 :#: \
$C1 :####: \
$C1 :#######: \
$C1 :#########: \
$C1 :#########: \
$C1 :#######: \
$C1 :####: \
$C1 :#: \
$C1:##: :#: \
$C1:####: :###: \
$C1:#######: :####: \
$C1:##########: :###: \
$C1:###########: :#: \
$C1:###########: \
$C1 :##########: \
$C1 :#######: \
$C1 :####: \
$C1 :##: "
// --------------------- LONG LOGOS ------------------------- //
#define ASCII_AMD_L \
"$C1 \
@@ -624,6 +644,7 @@ asciiL logo_ampere = { ASCII_AMPERE, 50, 17, false, {C_FG_RED},
asciiL logo_nxp = { ASCII_NXP, 55, 8, false, {C_FG_YELLOW, C_FG_CYAN, C_FG_GREEN}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_amlogic = { ASCII_AMLOGIC, 58, 8, false, {C_FG_BLUE}, {C_FG_BLUE, C_FG_B_WHITE} };
asciiL logo_marvell = { ASCII_MARVELL, 56, 10, false, {C_FG_B_BLACK}, {C_FG_B_BLACK, C_FG_B_WHITE} };
asciiL logo_spacemit = { ASCII_SPACEMIT, 27, 18, false, {C_FG_B_GREEN}, {C_FG_B_GREEN, C_FG_B_WHITE} };
// Long variants | ----------------------------------------------------------------------------------------------------------------|
asciiL logo_amd_l = { ASCII_AMD_L, 62, 19, true, {C_BG_WHITE, C_BG_GREEN}, {C_FG_WHITE, C_FG_GREEN} };

View File

@@ -25,6 +25,7 @@ enum {
CPU_VENDOR_RISCV,
CPU_VENDOR_SIFIVE,
CPU_VENDOR_THEAD,
CPU_VENDOR_SPACEMIT,
// OTHERS
CPU_VENDOR_UNKNOWN,
CPU_VENDOR_INVALID

View File

@@ -20,6 +20,7 @@
#include "../arm/uarch.h"
#include "../arm/midr.h"
#include "../arm/soc.h"
#include "../arm/socs.h"
#include "../common/soc.h"
#elif ARCH_RISCV
#include "../riscv/riscv.h"
@@ -44,9 +45,17 @@
#define MAX_ATTRIBUTES 100
#define MAX_TERM_SIZE 1024
typedef struct {
int id;
const char *name;
const char *shortname;
} AttributeField;
enum {
#if defined(ARCH_X86) || defined(ARCH_PPC)
#if defined(ARCH_X86)
ATTRIBUTE_NAME,
#elif defined(ARCH_PPC)
ATTRIBUTE_PART_NUMBER,
#elif defined(ARCH_ARM) || defined(ARCH_RISCV)
ATTRIBUTE_SOC,
#endif
@@ -78,76 +87,40 @@ enum {
ATTRIBUTE_PEAK
};
static const char* ATTRIBUTE_FIELDS [] = {
#ifdef ARCH_X86
"Name:",
#elif ARCH_PPC
"Part Number:",
#elif defined(ARCH_ARM) || defined(ARCH_RISCV)
"SoC:",
#endif
#if defined(ARCH_X86) || defined(ARCH_ARM)
"",
#endif
"Hypervisor:",
"Microarchitecture:",
"Technology:",
"Max Frequency:",
"Sockets:",
"Cores:",
"Cores (Total):",
#ifdef ARCH_X86
"SSE:",
"AVX:",
"FMA:",
#elif ARCH_PPC
"Altivec: ",
#elif defined(ARCH_ARM)
"Features: ",
#elif defined(ARCH_RISCV)
"Extensions: ",
#endif
"L1i Size:",
"L1d Size:",
"L2 Size:",
"L3 Size:",
"Peak Performance:",
};
static const char* ATTRIBUTE_FIELDS_SHORT [] = {
static const AttributeField ATTRIBUTE_INFO[] = {
#if defined(ARCH_X86)
"Name:",
#elif ARCH_PPC
"P/N:",
#elif ARCH_ARM
"SoC:",
{ ATTRIBUTE_NAME, "Name:", "Name:" },
#elif defined(ARCH_PPC)
{ ATTRIBUTE_PART_NUMBER, "Part Number:", "P/N:" },
#elif defined(ARCH_ARM) || defined(ARCH_RISCV)
{ ATTRIBUTE_SOC, "SoC:", "SoC:" },
#endif
#if defined(ARCH_X86) || defined(ARCH_ARM)
"",
{ ATTRIBUTE_CPU_NUM, "", "" },
#endif
"Hypervisor:",
"uArch:",
"Technology:",
"Max Freq:",
"Sockets:",
"Cores:",
"Cores (Total):",
{ ATTRIBUTE_HYPERVISOR, "Hypervisor:", "Hypervisor:" },
{ ATTRIBUTE_UARCH, "Microarchitecture:", "uArch:" },
{ ATTRIBUTE_TECHNOLOGY, "Technology:", "Technology:" },
{ ATTRIBUTE_FREQUENCY, "Max Frequency:", "Max Freq:" },
{ ATTRIBUTE_SOCKETS, "Sockets:", "Sockets:" },
{ ATTRIBUTE_NCORES, "Cores:", "Cores:" },
{ ATTRIBUTE_NCORES_DUAL, "Cores (Total):", "Cores (Total):" },
#ifdef ARCH_X86
"SSE:",
"AVX:",
"FMA:",
{ ATTRIBUTE_SSE, "SSE:", "SSE:" },
{ ATTRIBUTE_AVX, "AVX:", "AVX:" },
{ ATTRIBUTE_FMA, "FMA:", "FMA:" },
#elif ARCH_PPC
"Altivec: ",
#elif defined(ARCH_ARM)
"Features: ",
#elif defined(ARCH_RISCV)
"Extensions: ",
{ ATTRIBUTE_ALTIVEC, "Altivec: ", "Altivec: " },
#elif ARCH_ARM
{ ATTRIBUTE_FEATURES, "Features: ", "Features: " },
#elif ARCH_RISCV
{ ATTRIBUTE_EXTENSIONS, "Extensions: ", "Extensions: " },
#endif
"L1i Size:",
"L1d Size:",
"L2 Size:",
"L3 Size:",
"Peak Perf.:",
{ ATTRIBUTE_L1i, "L1i Size:", "L1i Size:" },
{ ATTRIBUTE_L1d, "L1d Size:", "L1d Size:" },
{ ATTRIBUTE_L2, "L2 Size:", "L2 Size:" },
{ ATTRIBUTE_L3, "L3 Size:", "L3 Size:" },
{ ATTRIBUTE_PEAK, "Peak Performance:", "Peak Perf.:" },
};
struct terminal {
@@ -411,6 +384,8 @@ void choose_ascii_art(struct ascii* art, struct color** cs, struct terminal* ter
art->art = &logo_allwinner;
else if(art->vendor == SOC_VENDOR_SIPEED)
art->art = &logo_sipeed;
else if(art->vendor == SOC_VENDOR_SPACEMIT)
art->art = &logo_spacemit;
else
art->art = &logo_riscv;
#endif
@@ -451,13 +426,14 @@ void choose_ascii_art(struct ascii* art, struct color** cs, struct terminal* ter
}
}
uint32_t longest_attribute_length(struct ascii* art, const char** attribute_fields) {
uint32_t longest_attribute_length(struct ascii* art, bool use_short) {
uint32_t max = 0;
uint64_t len = 0;
for(uint32_t i=0; i < art->n_attributes_set; i++) {
if(art->attributes[i]->value != NULL) {
len = strlen(attribute_fields[art->attributes[i]->type]);
const char* str = use_short ? ATTRIBUTE_INFO[art->attributes[i]->type].shortname : ATTRIBUTE_INFO[art->attributes[i]->type].name;
len = strlen(str);
if(len > max) max = len;
}
}
@@ -482,7 +458,7 @@ uint32_t longest_field_length(struct ascii* art, int la) {
}
#if defined(ARCH_X86) || defined(ARCH_PPC)
void print_ascii_generic(struct ascii* art, uint32_t la, int32_t termw, const char** attribute_fields, bool hybrid_architecture) {
void print_ascii_generic(struct ascii* art, uint32_t la, int32_t termw, bool use_short, bool hybrid_architecture) {
struct ascii_logo* logo = art->art;
int attr_to_print = 0;
int attr_type;
@@ -544,14 +520,15 @@ void print_ascii_generic(struct ascii* art, uint32_t la, int32_t termw, const ch
else {
#endif
beg_space = 0;
space_right = 2 + 1 + (la - strlen(attribute_fields[attr_type]));
const char* attr_str = use_short ? ATTRIBUTE_INFO[attr_type].shortname : ATTRIBUTE_INFO[attr_type].name;
space_right = 2 + 1 + (la - strlen(attr_str));
if(hybrid_architecture && add_space) {
beg_space = 2;
space_right -= 2;
}
printOut(lbuf, beg_space + strlen(attribute_fields[attr_type]) + space_right + strlen(attr_value),
"%*s%s%s%s%*s%s%s%s", beg_space, "", logo->color_text[0], attribute_fields[attr_type], art->reset, space_right, "", logo->color_text[1], attr_value, art->reset);
printOut(lbuf, beg_space + strlen(attr_str) + space_right + strlen(attr_value),
"%*s%s%s%s%*s%s%s%s", beg_space, "", logo->color_text[0], attr_str, art->reset, space_right, "", logo->color_text[1], attr_value, art->reset);
#ifdef ARCH_X86
}
#endif
@@ -660,19 +637,19 @@ bool print_cpufetch_x86(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
setAttribute(art, ATTRIBUTE_PEAK, pp);
// Step 3. Print output
const char** attribute_fields = ATTRIBUTE_FIELDS;
uint32_t longest_attribute = longest_attribute_length(art, attribute_fields);
bool use_short = false;
uint32_t longest_attribute = longest_attribute_length(art, use_short);
uint32_t longest_field = longest_field_length(art, longest_attribute);
choose_ascii_art(art, cs, term, longest_field);
if(!ascii_fits_screen(term->w, *art->art, longest_field)) {
// Despite of choosing the smallest logo, the output does not fit
// Choose the shorter field names and recalculate the longest attr
attribute_fields = ATTRIBUTE_FIELDS_SHORT;
longest_attribute = longest_attribute_length(art, attribute_fields);
use_short = true;
longest_attribute = longest_attribute_length(art, use_short);
}
print_ascii_generic(art, longest_attribute, term->w, attribute_fields, hybrid_architecture);
print_ascii_generic(art, longest_attribute, term->w, use_short, hybrid_architecture);
free(manufacturing_process);
free(sockets);
@@ -721,7 +698,7 @@ bool print_cpufetch_ppc(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
// Step 2. Set attributes
if(cpu_name != NULL) {
setAttribute(art, ATTRIBUTE_NAME, cpu_name);
setAttribute(art, ATTRIBUTE_PART_NUMBER, cpu_name);
}
setAttribute(art, ATTRIBUTE_UARCH, uarch);
if(cpu->hv->present) {
@@ -748,19 +725,19 @@ bool print_cpufetch_ppc(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
setAttribute(art, ATTRIBUTE_PEAK, pp);
// Step 3. Print output
const char** attribute_fields = ATTRIBUTE_FIELDS;
uint32_t longest_attribute = longest_attribute_length(art, attribute_fields);
bool use_short = false;
uint32_t longest_attribute = longest_attribute_length(art, use_short);
uint32_t longest_field = longest_field_length(art, longest_attribute);
choose_ascii_art(art, cs, term, longest_field);
if(!ascii_fits_screen(term->w, *art->art, longest_field)) {
// Despite of choosing the smallest logo, the output does not fit
// Choose the shorter field names and recalculate the longest attr
attribute_fields = ATTRIBUTE_FIELDS_SHORT;
longest_attribute = longest_attribute_length(art, attribute_fields);
use_short = true;
longest_attribute = longest_attribute_length(art, use_short);
}
print_ascii_generic(art, longest_attribute, term->w, attribute_fields, false);
print_ascii_generic(art, longest_attribute, term->w, use_short, false);
return true;
}
@@ -788,7 +765,7 @@ uint32_t longest_field_length_arm(struct ascii* art, int la) {
return max;
}
void print_ascii_arm(struct ascii* art, uint32_t la, int32_t termw, const char** attribute_fields) {
void print_ascii_arm(struct ascii* art, uint32_t la, int32_t termw, bool use_short) {
struct ascii_logo* logo = art->art;
int attr_to_print = 0;
int attr_type;
@@ -859,14 +836,15 @@ void print_ascii_arm(struct ascii* art, uint32_t la, int32_t termw, const char**
}
else {
beg_space = 0;
space_right = 2 + 1 + (la - strlen(attribute_fields[attr_type]));
const char* attr_str = use_short ? ATTRIBUTE_INFO[attr_type].shortname : ATTRIBUTE_INFO[attr_type].name;
space_right = 2 + 1 + (la - strlen(attr_str));
if(add_space) {
beg_space = 2;
space_right -= 2;
}
printOut(lbuf, beg_space + strlen(attribute_fields[attr_type]) + space_right + strlen(attr_value),
"%*s%s%s%s%*s%s%s%s", beg_space, "", logo->color_text[0], attribute_fields[attr_type], art->reset, space_right, "", logo->color_text[1], attr_value, art->reset);
printOut(lbuf, beg_space + strlen(attr_str) + space_right + strlen(attr_value),
"%*s%s%s%s%*s%s%s%s", beg_space, "", logo->color_text[0], attr_str, art->reset, space_right, "", logo->color_text[1], attr_value, art->reset);
}
}
printOutLine(lbuf, art, termw);
@@ -892,6 +870,11 @@ bool print_cpufetch_arm(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
// https://github.com/Dr-Noob/cpufetch/pull/273
// Hide manufacturing process
#if !defined(_WIN32)
// In the case that the model is unknown but the vendor isn't (this is, when
// guess_raw_soc_from_devtree succeeded), do not show the manufacturing process
// (as it will be unknown)
if (cpu->soc->model != SOC_MODEL_UNKNOWN ||
(cpu->soc->model == SOC_MODEL_UNKNOWN && cpu->soc->vendor == SOC_VENDOR_UNKNOWN))
setAttribute(art, ATTRIBUTE_TECHNOLOGY, manufacturing_process);
#endif
@@ -931,8 +914,8 @@ bool print_cpufetch_arm(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
setAttribute(art, ATTRIBUTE_HYPERVISOR, cpu->hv->hv_name);
}
const char** attribute_fields = ATTRIBUTE_FIELDS;
uint32_t longest_attribute = longest_attribute_length(art, attribute_fields);
bool use_short = false;
uint32_t longest_attribute = longest_attribute_length(art, use_short);
uint32_t longest_field = longest_field_length_arm(art, longest_attribute);
choose_ascii_art(art, cs, term, longest_field);
@@ -944,11 +927,11 @@ bool print_cpufetch_arm(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
if(!ascii_fits_screen(term->w, *art->art, longest_field)) {
// Despite of choosing the smallest logo, the output does not fit
// Choose the shorter field names and recalculate the longest attr
attribute_fields = ATTRIBUTE_FIELDS_SHORT;
longest_attribute = longest_attribute_length(art, attribute_fields);
use_short = true;
longest_attribute = longest_attribute_length(art, use_short);
}
print_ascii_arm(art, longest_attribute, term->w, attribute_fields);
print_ascii_arm(art, longest_attribute, term->w, use_short);
free(manufacturing_process);
free(pp);
@@ -973,7 +956,7 @@ uint64_t number_of_bits(uint64_t i) {
return (((i + (i >> 4)) & 0xF0F0F0F0F0F0F0F) * 0x101010101010101) >> 56;
}
void print_ascii_riscv(struct ascii* art, uint32_t la, int32_t termw, const char** attribute_fields, uint64_t extensions_mask) {
void print_ascii_riscv(struct ascii* art, uint32_t la, int32_t termw, bool use_short, uint64_t extensions_mask) {
struct ascii_logo* logo = art->art;
int attr_to_print = 0;
int attr_type;
@@ -1041,10 +1024,11 @@ void print_ascii_riscv(struct ascii* art, uint32_t la, int32_t termw, const char
else {
attr_to_print++;
beg_space = 0;
space_right = 2 + 1 + (la - strlen(attribute_fields[attr_type]));
const char* attr_str = use_short ? ATTRIBUTE_INFO[attr_type].shortname : ATTRIBUTE_INFO[attr_type].name;
space_right = 2 + 1 + (la - strlen(attr_str));
printOut(lbuf, beg_space + strlen(attribute_fields[attr_type]) + space_right + strlen(attr_value),
"%*s%s%s%s%*s%s%s%s", beg_space, "", logo->color_text[0], attribute_fields[attr_type], art->reset, space_right, "", logo->color_text[1], attr_value, art->reset);
printOut(lbuf, beg_space + strlen(attr_str) + space_right + strlen(attr_value),
"%*s%s%s%s%*s%s%s%s", beg_space, "", logo->color_text[0], attr_str, art->reset, space_right, "", logo->color_text[1], attr_value, art->reset);
}
}
printOutLine(lbuf, art, termw);
@@ -1082,19 +1066,19 @@ bool print_cpufetch_riscv(struct cpuInfo* cpu, STYLE s, struct color** cs, struc
setAttribute(art, ATTRIBUTE_PEAK, pp);
// Step 3. Print output
const char** attribute_fields = ATTRIBUTE_FIELDS;
uint32_t longest_attribute = longest_attribute_length(art, attribute_fields);
bool use_short = false;
uint32_t longest_attribute = longest_attribute_length(art, use_short);
uint32_t longest_field = longest_field_length(art, longest_attribute);
choose_ascii_art(art, cs, term, longest_field);
if(!ascii_fits_screen(term->w, *art->art, longest_field)) {
// Despite of choosing the smallest logo, the output does not fit
// Choose the shorter field names and recalculate the longest attr
attribute_fields = ATTRIBUTE_FIELDS_SHORT;
longest_attribute = longest_attribute_length(art, attribute_fields);
use_short = true;
longest_attribute = longest_attribute_length(art, use_short);
}
print_ascii_riscv(art, longest_attribute, term->w, attribute_fields, cpu->ext->mask);
print_ascii_riscv(art, longest_attribute, term->w, use_short, cpu->ext->mask);
return true;
}

View File

@@ -29,6 +29,7 @@ static char* soc_trademark_string[] = {
[SOC_VENDOR_SIFIVE] = "SiFive ",
[SOC_VENDOR_STARFIVE] = "StarFive ",
[SOC_VENDOR_SIPEED] = "Sipeed ",
[SOC_VENDOR_SPACEMIT] = "SpacemiT ",
// ARM & RISC-V
[SOC_VENDOR_ALLWINNER] = "Allwinner "
};
@@ -85,8 +86,8 @@ void fill_soc_raw(struct system_on_chip* soc, char* soc_name, VENDOR vendor) {
soc->process = UNKNOWN;
int len = strlen(soc_name) + strlen(soc_trademark_string[soc->vendor]) + 1;
soc->name = emalloc(sizeof(char) * len);
sprintf(soc->name, "%s%s", soc_trademark_string[soc->vendor], soc_name);
soc->raw_name = emalloc(sizeof(char) * len);
sprintf(soc->raw_name, "%s%s", soc_trademark_string[soc->vendor], soc_name);
}
#ifdef _WIN32

View File

@@ -33,6 +33,7 @@ enum {
SOC_VENDOR_SIFIVE,
SOC_VENDOR_STARFIVE,
SOC_VENDOR_SIPEED,
SOC_VENDOR_SPACEMIT,
// ARM & RISC-V
SOC_VENDOR_ALLWINNER
};

View File

@@ -362,12 +362,13 @@ char* get_devtree_compatible(int *filelen) {
return buf;
}
// TODO:
// Returns a list of strings containing the vendors of the compatible
// file from the device tree. In this context, vendor refers to the first
// string of every entry. For instance, given a compatible file with:
// Returns a list of structs devtree, each containing both the vendor and the
// model, coming from the compatible file from the device tree. In this
// context, vendor refers to the first string of every entry and the model to
// the second. For instance, given a compatible file with:
// "str1,foo1.str2,foo2" (where . denotes the NULL byte, i.e., the separator),
// then this function will return a list with str1,str2.
// then this function will return a list with two structs, the first one
// containing str1 and foo1 and the other containing str2 and foo2.
struct devtree** get_devtree_compatible_struct(int *num_vendors_ptr) {
int len;
char* dt = get_devtree_compatible(&len);
@@ -379,7 +380,12 @@ struct devtree** get_devtree_compatible_struct(int *num_vendors_ptr) {
char* ptr = dt;
for (int ptrpos = 0; ptrpos < len; ptrpos = (ptr-dt)) {
ptr = memchr(ptr, '\0', len)+1;
ptr = memchr(ptr, '\0', len);
if (ptr == NULL) {
printBug("get_devtree_compatible_struct: Unable to find delimiter (1) (num_vendors=%d)", num_vendors);
return NULL;
}
ptr++;
num_vendors++;
}
@@ -387,21 +393,35 @@ struct devtree** get_devtree_compatible_struct(int *num_vendors_ptr) {
ptr = dt;
for (int ptrpos = 0, i = 0; ptrpos < len; ptrpos = (ptr-dt), i++) {
char* comma_ptr = strstr(ptr, ",")-1;
char* end_ptr = memchr(comma_ptr, '\0', ptrpos - len);
char* comma_ptr = strstr(ptr, ",");
if (comma_ptr == NULL) {
printBug("get_devtree_compatible_struct: Unable to find comma (num_vendors=%d)", num_vendors);
return NULL;
}
comma_ptr = comma_ptr-1; // Point right before comma
char* end_ptr = memchr(comma_ptr, '\0', len - ptrpos);
if (end_ptr == NULL) {
printBug("get_devtree_compatible_struct: Unable to find delimiter (2) (num_vendors=%d)", num_vendors);
return NULL;
}
// TODO check NULL
int vendor_str_len = (comma_ptr-ptr)+1;
int model_str_len = (end_ptr-comma_ptr)+1;
int model_str_len = (end_ptr-(comma_ptr+2))+1;
vendors[i] = emalloc(sizeof(struct devtree));
vendors[i]->vendor = ecalloc(vendor_str_len, sizeof(char));
vendors[i]->model = ecalloc(model_str_len, sizeof(char));
strncpy(vendors[i]->vendor, ptr, vendor_str_len);
strncpy(vendors[i]->model, comma_ptr, model_str_len);
strncpy(vendors[i]->model, comma_ptr+2, model_str_len);
ptr = memchr(ptr, '\0', len)+1;
ptr = memchr(ptr, '\0', len);
if (ptr == NULL) {
printBug("get_devtree_compatible_struct: Unable to find delimiter (3) (num_vendors=%d)", num_vendors);
return NULL;
}
ptr++; // Point right after delimiter
}
*num_vendors_ptr = num_vendors;

View File

@@ -72,6 +72,65 @@ int parse_multi_letter_extension(struct extensions* ext, char* e) {
SET_ISA_EXT_MAP("zicsr", RISCV_ISA_EXT_ZICSR)
SET_ISA_EXT_MAP("zifencei", RISCV_ISA_EXT_ZIFENCEI)
SET_ISA_EXT_MAP("zihpm", RISCV_ISA_EXT_ZIHPM)
SET_ISA_EXT_MAP("smstateen", RISCV_ISA_EXT_SMSTATEEN)
SET_ISA_EXT_MAP("zicond", RISCV_ISA_EXT_ZICOND)
SET_ISA_EXT_MAP("zbc", RISCV_ISA_EXT_ZBC)
SET_ISA_EXT_MAP("zbkb", RISCV_ISA_EXT_ZBKB)
SET_ISA_EXT_MAP("zbkc", RISCV_ISA_EXT_ZBKC)
SET_ISA_EXT_MAP("zbkx", RISCV_ISA_EXT_ZBKX)
SET_ISA_EXT_MAP("zknd", RISCV_ISA_EXT_ZKND)
SET_ISA_EXT_MAP("zkne", RISCV_ISA_EXT_ZKNE)
SET_ISA_EXT_MAP("zknh", RISCV_ISA_EXT_ZKNH)
SET_ISA_EXT_MAP("zkr", RISCV_ISA_EXT_ZKR)
SET_ISA_EXT_MAP("zksed", RISCV_ISA_EXT_ZKSED)
SET_ISA_EXT_MAP("zksh", RISCV_ISA_EXT_ZKSH)
SET_ISA_EXT_MAP("zkt", RISCV_ISA_EXT_ZKT)
SET_ISA_EXT_MAP("zvbb", RISCV_ISA_EXT_ZVBB)
SET_ISA_EXT_MAP("zvbc", RISCV_ISA_EXT_ZVBC)
SET_ISA_EXT_MAP("zvkb", RISCV_ISA_EXT_ZVKB)
SET_ISA_EXT_MAP("zvkg", RISCV_ISA_EXT_ZVKG)
SET_ISA_EXT_MAP("zvkned", RISCV_ISA_EXT_ZVKNED)
SET_ISA_EXT_MAP("zvknha", RISCV_ISA_EXT_ZVKNHA)
SET_ISA_EXT_MAP("zvknhb", RISCV_ISA_EXT_ZVKNHB)
SET_ISA_EXT_MAP("zvksed", RISCV_ISA_EXT_ZVKSED)
SET_ISA_EXT_MAP("zvksh", RISCV_ISA_EXT_ZVKSH)
SET_ISA_EXT_MAP("zvkt", RISCV_ISA_EXT_ZVKT)
SET_ISA_EXT_MAP("zfh", RISCV_ISA_EXT_ZFH)
SET_ISA_EXT_MAP("zfhmin", RISCV_ISA_EXT_ZFHMIN)
SET_ISA_EXT_MAP("zihintntl", RISCV_ISA_EXT_ZIHINTNTL)
SET_ISA_EXT_MAP("zvfh", RISCV_ISA_EXT_ZVFH)
SET_ISA_EXT_MAP("zvfhmin", RISCV_ISA_EXT_ZVFHMIN)
SET_ISA_EXT_MAP("zfa", RISCV_ISA_EXT_ZFA)
SET_ISA_EXT_MAP("ztso", RISCV_ISA_EXT_ZTSO)
SET_ISA_EXT_MAP("zacas", RISCV_ISA_EXT_ZACAS)
SET_ISA_EXT_MAP("zve32x", RISCV_ISA_EXT_ZVE32X)
SET_ISA_EXT_MAP("zve32f", RISCV_ISA_EXT_ZVE32F)
SET_ISA_EXT_MAP("zve64x", RISCV_ISA_EXT_ZVE64X)
SET_ISA_EXT_MAP("zve64f", RISCV_ISA_EXT_ZVE64F)
SET_ISA_EXT_MAP("zve64d", RISCV_ISA_EXT_ZVE64D)
SET_ISA_EXT_MAP("zimop", RISCV_ISA_EXT_ZIMOP)
SET_ISA_EXT_MAP("zca", RISCV_ISA_EXT_ZCA)
SET_ISA_EXT_MAP("zcb", RISCV_ISA_EXT_ZCB)
SET_ISA_EXT_MAP("zcd", RISCV_ISA_EXT_ZCD)
SET_ISA_EXT_MAP("zcf", RISCV_ISA_EXT_ZCF)
SET_ISA_EXT_MAP("zcmop", RISCV_ISA_EXT_ZCMOP)
SET_ISA_EXT_MAP("zawrs", RISCV_ISA_EXT_ZAWRS)
SET_ISA_EXT_MAP("svvptc", RISCV_ISA_EXT_SVVPTC)
SET_ISA_EXT_MAP("smmpm", RISCV_ISA_EXT_SMMPM)
SET_ISA_EXT_MAP("smnpm", RISCV_ISA_EXT_SMNPM)
SET_ISA_EXT_MAP("ssnpm", RISCV_ISA_EXT_SSNPM)
SET_ISA_EXT_MAP("zabha", RISCV_ISA_EXT_ZABHA)
SET_ISA_EXT_MAP("ziccrse", RISCV_ISA_EXT_ZICCRSE)
SET_ISA_EXT_MAP("svade", RISCV_ISA_EXT_SVADE)
SET_ISA_EXT_MAP("svadu", RISCV_ISA_EXT_SVADU)
SET_ISA_EXT_MAP("zfbfmin", RISCV_ISA_EXT_ZFBFMIN)
SET_ISA_EXT_MAP("zvfbfmin", RISCV_ISA_EXT_ZVFBFMIN)
SET_ISA_EXT_MAP("zvfbfwma", RISCV_ISA_EXT_ZVFBFWMA)
SET_ISA_EXT_MAP("zaamo", RISCV_ISA_EXT_ZAAMO)
SET_ISA_EXT_MAP("zalrsc", RISCV_ISA_EXT_ZALRSC)
SET_ISA_EXT_MAP("zicbop", RISCV_ISA_EXT_ZICBOP)
SET_ISA_EXT_MAP("ime", RISCV_ISA_EXT_IME)
if(!maskset) {
printBug("parse_multi_letter_extension: Unknown multi-letter extension: %s", multi_letter_extension);
return -1;
@@ -101,8 +160,8 @@ struct extensions* get_extensions_from_str(char* str) {
return ext;
}
int len = strlen(str);
ext->str = ecalloc(len+1, sizeof(char));
int len = strlen(str)+1;
ext->str = emalloc(len * sizeof(char));
strncpy(ext->str, str, sizeof(char) * len);
// Code inspired in Linux kernel (riscv_fill_hwcap):
@@ -157,13 +216,12 @@ struct cpuInfo* get_cpu_info(void) {
topo->cach = NULL;
cpu->topo = topo;
char* cpuinfo_str = get_uarch_from_cpuinfo();
char* ext_str = get_extensions_from_cpuinfo();
cpu->hv = emalloc(sizeof(struct hypervisor));
cpu->hv->present = false;
cpu->ext = get_extensions_from_str(ext_str);
if(cpu->ext->str != NULL && cpu->ext->mask == 0) return NULL;
cpu->arch = get_uarch_from_cpuinfo_str(cpuinfo_str, cpu);
cpu->arch = get_uarch(cpu);
cpu->soc = get_soc(cpu);
cpu->freq = get_frequency_info(0);
cpu->peak_performance = get_peak_performance(cpu);

View File

@@ -23,7 +23,6 @@ enum riscv_isa_ext_id {
RISCV_ISA_EXT_ZICBOM,
RISCV_ISA_EXT_ZIHINTPAUSE,
RISCV_ISA_EXT_SVNAPOT,
RISCV_ISA_EXT_ZICBOP,
RISCV_ISA_EXT_ZICBOZ,
RISCV_ISA_EXT_SMAIA,
RISCV_ISA_EXT_SSAIA,
@@ -33,12 +32,71 @@ enum riscv_isa_ext_id {
RISCV_ISA_EXT_ZICSR,
RISCV_ISA_EXT_ZIFENCEI,
RISCV_ISA_EXT_ZIHPM,
RISCV_ISA_EXT_SMSTATEEN,
RISCV_ISA_EXT_ZICOND,
RISCV_ISA_EXT_ZBC,
RISCV_ISA_EXT_ZBKB,
RISCV_ISA_EXT_ZBKC,
RISCV_ISA_EXT_ZBKX,
RISCV_ISA_EXT_ZKND,
RISCV_ISA_EXT_ZKNE,
RISCV_ISA_EXT_ZKNH,
RISCV_ISA_EXT_ZKR,
RISCV_ISA_EXT_ZKSED,
RISCV_ISA_EXT_ZKSH,
RISCV_ISA_EXT_ZKT,
RISCV_ISA_EXT_ZVBB,
RISCV_ISA_EXT_ZVBC,
RISCV_ISA_EXT_ZVKB,
RISCV_ISA_EXT_ZVKG,
RISCV_ISA_EXT_ZVKNED,
RISCV_ISA_EXT_ZVKNHA,
RISCV_ISA_EXT_ZVKNHB,
RISCV_ISA_EXT_ZVKSED,
RISCV_ISA_EXT_ZVKSH,
RISCV_ISA_EXT_ZVKT,
RISCV_ISA_EXT_ZFH,
RISCV_ISA_EXT_ZFHMIN,
RISCV_ISA_EXT_ZIHINTNTL,
RISCV_ISA_EXT_ZVFH,
RISCV_ISA_EXT_ZVFHMIN,
RISCV_ISA_EXT_ZFA,
RISCV_ISA_EXT_ZTSO,
RISCV_ISA_EXT_ZACAS,
RISCV_ISA_EXT_ZVE32X,
RISCV_ISA_EXT_ZVE32F,
RISCV_ISA_EXT_ZVE64X,
RISCV_ISA_EXT_ZVE64F,
RISCV_ISA_EXT_ZVE64D,
RISCV_ISA_EXT_ZIMOP,
RISCV_ISA_EXT_ZCA,
RISCV_ISA_EXT_ZCB,
RISCV_ISA_EXT_ZCD,
RISCV_ISA_EXT_ZCF,
RISCV_ISA_EXT_ZCMOP,
RISCV_ISA_EXT_ZAWRS,
RISCV_ISA_EXT_SVVPTC,
RISCV_ISA_EXT_SMMPM,
RISCV_ISA_EXT_SMNPM,
RISCV_ISA_EXT_SSNPM,
RISCV_ISA_EXT_ZABHA,
RISCV_ISA_EXT_ZICCRSE,
RISCV_ISA_EXT_SVADE,
RISCV_ISA_EXT_SVADU,
RISCV_ISA_EXT_ZFBFMIN,
RISCV_ISA_EXT_ZVFBFMIN,
RISCV_ISA_EXT_ZVFBFWMA,
RISCV_ISA_EXT_ZAAMO,
RISCV_ISA_EXT_ZALRSC,
RISCV_ISA_EXT_ZICBOP,
RISCV_ISA_EXT_IME,
RISCV_ISA_EXT_ID_MAX
};
// https://five-embeddev.com/riscv-isa-manual/latest/preface.html#preface
// https://en.wikichip.org/wiki/risc-v/standard_extensions
// (Zicbop) https://github.com/riscv/riscv-CMOs/blob/master/cmobase/Zicbop.adoc
// https://raw.githubusercontent.com/riscv/riscv-CMOs/master/specifications/cmobase-v1.0.1.pdf
// Included all except for G
static const struct extension extension_list[] = {
{ 'i' - 'a', "(I) Integer Instruction Set" },
@@ -74,7 +132,65 @@ static const struct extension extension_list[] = {
{ RISCV_ISA_EXT_ZICNTR, "(Zicntr) Base Counters and Timers" },
{ RISCV_ISA_EXT_ZICSR, "(Zicsr) Control and Status Register" },
{ RISCV_ISA_EXT_ZIFENCEI, "(Zifencei) Instruction-Fetch Fence" },
{ RISCV_ISA_EXT_ZIHPM, "(Zihpm) Hardware Performance Counters" }
{ RISCV_ISA_EXT_ZIHPM, "(Zihpm) Hardware Performance Counters" },
{ RISCV_ISA_EXT_SMSTATEEN, "(smstateen) " },
{ RISCV_ISA_EXT_ZICOND, "(zicond) " },
{ RISCV_ISA_EXT_ZBC, "(zbc) " },
{ RISCV_ISA_EXT_ZBKB, "(zbkb) " },
{ RISCV_ISA_EXT_ZBKC, "(zbkc) " },
{ RISCV_ISA_EXT_ZBKX, "(zbkx) " },
{ RISCV_ISA_EXT_ZKND, "(zknd) " },
{ RISCV_ISA_EXT_ZKNE, "(zkne) " },
{ RISCV_ISA_EXT_ZKNH, "(zknh) " },
{ RISCV_ISA_EXT_ZKR, "(zkr) " },
{ RISCV_ISA_EXT_ZKSED, "(zksed) " },
{ RISCV_ISA_EXT_ZKSH, "(zksh) " },
{ RISCV_ISA_EXT_ZKT, "(zkt) " },
{ RISCV_ISA_EXT_ZVBB, "(zvbb) " },
{ RISCV_ISA_EXT_ZVBC, "(zvbc) " },
{ RISCV_ISA_EXT_ZVKB, "(zvkb) " },
{ RISCV_ISA_EXT_ZVKG, "(zvkg) " },
{ RISCV_ISA_EXT_ZVKNED, "(zvkned) " },
{ RISCV_ISA_EXT_ZVKNHA, "(zvknha) " },
{ RISCV_ISA_EXT_ZVKNHB, "(zvknhb) " },
{ RISCV_ISA_EXT_ZVKSED, "(zvksed) " },
{ RISCV_ISA_EXT_ZVKSH, "(zvksh) " },
{ RISCV_ISA_EXT_ZVKT, "(zvkt) " },
{ RISCV_ISA_EXT_ZFH, "(zfh) " },
{ RISCV_ISA_EXT_ZFHMIN, "(zfhmin) " },
{ RISCV_ISA_EXT_ZIHINTNTL, "(zihintntl) " },
{ RISCV_ISA_EXT_ZVFH, "(zvfh) " },
{ RISCV_ISA_EXT_ZVFHMIN, "(zvfhmin) " },
{ RISCV_ISA_EXT_ZFA, "(zfa) " },
{ RISCV_ISA_EXT_ZTSO, "(ztso) " },
{ RISCV_ISA_EXT_ZACAS, "(zacas) " },
{ RISCV_ISA_EXT_ZVE32X, "(zve32x) " },
{ RISCV_ISA_EXT_ZVE32F, "(zve32f) " },
{ RISCV_ISA_EXT_ZVE64X, "(zve64x) " },
{ RISCV_ISA_EXT_ZVE64F, "(zve64f) " },
{ RISCV_ISA_EXT_ZVE64D, "(zve64d) " },
{ RISCV_ISA_EXT_ZIMOP, "(zimop) " },
{ RISCV_ISA_EXT_ZCA, "(zca) " },
{ RISCV_ISA_EXT_ZCB, "(zcb) " },
{ RISCV_ISA_EXT_ZCD, "(zcd) " },
{ RISCV_ISA_EXT_ZCF, "(zcf) " },
{ RISCV_ISA_EXT_ZCMOP, "(zcmop) " },
{ RISCV_ISA_EXT_ZAWRS, "(zawrs) " },
{ RISCV_ISA_EXT_SVVPTC, "(svvptc) " },
{ RISCV_ISA_EXT_SMMPM, "(smmpm) " },
{ RISCV_ISA_EXT_SMNPM, "(smnpm) " },
{ RISCV_ISA_EXT_SSNPM, "(ssnpm) " },
{ RISCV_ISA_EXT_ZABHA, "(zabha) " },
{ RISCV_ISA_EXT_ZICCRSE, "(ziccrse) " },
{ RISCV_ISA_EXT_SVADE, "(svade) " },
{ RISCV_ISA_EXT_SVADU, "(svadu) " },
{ RISCV_ISA_EXT_ZFBFMIN, "(zfbfmin) " },
{ RISCV_ISA_EXT_ZVFBFMIN, "(zvfbfmin) " },
{ RISCV_ISA_EXT_ZVFBFWMA, "(zvfbfwma) " },
{ RISCV_ISA_EXT_ZAAMO, "(zaamo) " },
{ RISCV_ISA_EXT_ZALRSC, "(zalrsc) " },
{ RISCV_ISA_EXT_ZICBOP, "(zicbop) " },
{ RISCV_ISA_EXT_IME, "(ime) Integrated Matrix Extension" },
};
struct cpuInfo* get_cpu_info(void);

View File

@@ -38,6 +38,12 @@ bool match_sipeed(char* soc_name, struct system_on_chip* soc) {
SOC_END
}
bool match_spacemit(char* soc_name, struct system_on_chip* soc) {
SOC_START
SOC_EQ(soc_name, "k1-x", "K1-X", SOC_SPACEMIT_K1X, soc, 22) // https://github.com/Dr-Noob/cpufetch/issues/286 https://www.spacemit.com/en/spacemit-x60-core/
SOC_END
}
struct system_on_chip* parse_soc_from_string(struct system_on_chip* soc) {
char* raw_name = soc->raw_name;
@@ -50,6 +56,9 @@ struct system_on_chip* parse_soc_from_string(struct system_on_chip* soc) {
if(match_sifive(raw_name, soc))
return soc;
if(match_spacemit(raw_name, soc))
return soc;
match_sipeed(raw_name, soc);
return soc;
}

View File

@@ -13,6 +13,8 @@ enum {
SOC_ALLWINNER_D1H,
// SIPEED
SOC_SIPEED_LICHEEPI4A,
// SPACEMIT
SOC_SPACEMIT_K1X,
// UNKNOWN
SOC_MODEL_UNKNOWN
};
@@ -22,6 +24,7 @@ inline static VENDOR get_soc_vendor_from_soc(SOC soc) {
if(soc >= SOC_STARFIVE_VF2 && soc <= SOC_STARFIVE_VF2) return SOC_VENDOR_STARFIVE;
if(soc >= SOC_ALLWINNER_D1H && soc <= SOC_ALLWINNER_D1H) return SOC_VENDOR_ALLWINNER;
if(soc >= SOC_SIPEED_LICHEEPI4A && soc <= SOC_SIPEED_LICHEEPI4A) return SOC_VENDOR_SIPEED;
if(soc >= SOC_SPACEMIT_K1X && soc <= SOC_SPACEMIT_K1X) return SOC_VENDOR_SPACEMIT;
return SOC_VENDOR_UNKNOWN;
}

View File

@@ -4,6 +4,7 @@
#include <string.h>
#include "uarch.h"
#include "udev.h"
#include "../common/global.h"
typedef uint32_t MICROARCH;
@@ -12,6 +13,7 @@ struct uarch {
MICROARCH uarch;
char* uarch_str;
char* cpuinfo_str;
struct riscv_cpuinfo* ci;
};
enum {
@@ -21,13 +23,20 @@ enum {
UARCH_U74,
// THEAD
UARCH_C906,
UARCH_C910
UARCH_C910,
// SPACEMIT
UARCH_X60
};
#define UARCH_START if (false) {}
#define CHECK_UARCH(arch, cpu, cpuinfo_str, uarch_str, str, uarch, vendor) \
else if (strcmp(cpuinfo_str, uarch_str) == 0) fill_uarch(arch, cpu, str, uarch, vendor);
#define UARCH_END else { printBug("Unknown microarchitecture detected: uarch='%s'", cpuinfo_str); fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); }
#define UARCH_END else { printWarn("Unknown microarchitecture detected: uarch='%s'", cpuinfo_str); fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); }
#define ARCHID_START if (false) {}
#define CHECK_ARCHID(arch, marchid_val, str, uarch, vendor) \
else if (arch->ci->marchid == (unsigned long) marchid_val) fill_uarch(arch, cpu, str, uarch, vendor);
#define ARCHID_END else { printWarn("Unknown microarchitecture detected: marchid=0x%.8X", arch->ci->marchid); fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); }
void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u, VENDOR vendor) {
arch->uarch = u;
@@ -39,14 +48,8 @@ void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u,
// https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml
// SiFive: https://www.sifive.com/risc-v-core-ip
// T-Head: https://www.t-head.cn/product/c906
struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu) {
struct uarch* arch = emalloc(sizeof(struct uarch));
struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu, struct uarch* arch) {
arch->cpuinfo_str = cpuinfo_str;
if(cpuinfo_str == NULL) {
printWarn("get_uarch_from_cpuinfo: Unable to detect microarchitecture, cpuinfo_str is NULL");
fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN);
return arch;
}
// U74/U74-MC:
// SiFive says that U74-MC is "Multicore: four U74 cores and one S76 core" while
@@ -70,6 +73,41 @@ struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu)
return arch;
}
// Use marchid to get the microarchitecture
struct uarch* get_uarch_from_riscv_cpuinfo(struct cpuInfo* cpu, struct uarch* arch) {
ARCHID_START
CHECK_ARCHID(arch, 0x8000000058000001, "X60", UARCH_X60, CPU_VENDOR_SPACEMIT) // https://github.com/Dr-Noob/cpufetch/issues/286
ARCHID_END
return arch;
}
struct uarch* get_uarch(struct cpuInfo* cpu) {
char* cpuinfo_str = get_uarch_from_cpuinfo();
struct uarch* arch = emalloc(sizeof(struct uarch));
arch->uarch = UARCH_UNKNOWN;
arch->ci = NULL;
if (cpuinfo_str == NULL) {
printWarn("get_uarch_from_cpuinfo: Unable to detect microarchitecture using uarch: cpuinfo_str is NULL");
arch->ci = get_riscv_cpuinfo();
if (arch->ci == NULL || arch->ci->marchid == 0)
printWarn("get_riscv_cpuinfo: Unable to get marchid from udev");
else
arch = get_uarch_from_riscv_cpuinfo(cpu, arch);
}
else {
arch = get_uarch_from_cpuinfo_str(cpuinfo_str, cpu, arch);
}
if (arch->uarch == UARCH_UNKNOWN)
fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN);
return arch;
}
char* get_str_uarch(struct cpuInfo* cpu) {
return cpu->arch->uarch_str;
}

View File

@@ -9,6 +9,6 @@ struct uarch;
char* get_arch_cpuinfo_str(struct cpuInfo* cpu);
char* get_str_uarch(struct cpuInfo* cpu);
void free_uarch_struct(struct uarch* arch);
struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu);
struct uarch* get_uarch(struct cpuInfo* cpu);
#endif

View File

@@ -7,6 +7,9 @@
#define _PATH_DEVTREE "/proc/device-tree/compatible"
#define CPUINFO_UARCH_STR "uarch\t\t: "
#define CPUINFO_EXTENSIONS_STR "isa\t\t: "
#define CPUINFO_RISCV_MVENDORID "mvendorid\t:"
#define CPUINFO_RISCV_MARCHID "marchid\t\t:"
#define CPUINFO_RISCV_MIMPID "mimpid\t\t:"
#define DEVTREE_HARDWARE_FIELD 0
char* get_field_from_devtree(int DEVTREE_FIELD) {
@@ -75,6 +78,52 @@ char* parse_cpuinfo_field(char* field_str) {
return ret;
}
unsigned long parse_cpuinfo_field_uint64(char* field_str) {
int filelen;
char* buf;
if((buf = read_file(_PATH_CPUINFO, &filelen)) == NULL) {
printWarn("read_file: %s: %s", _PATH_CPUINFO, strerror(errno));
return 0;
}
char* tmp = strstr(buf, field_str);
if(tmp == NULL) return 0;
tmp += strlen(field_str);
char* end;
errno = 0;
unsigned long ret = strtoul(tmp, &end, 16);
if (errno != 0) {
printWarn("strtoul: %s: %s", strerror(errno), tmp);
return 0;
}
return ret;
}
// Creates and fills in the riscv_cpuinfo struct (which contains
// mvendorid, marchid and mimpid) using cpuinfo to fetch the values.
//
// Every RISC-V hart (hardware thread) [1] provides a
// marchid (Machine Architecture ID register) CSR that encodes its
// base microarchitecture [2]. For more information about
// marchid and the rest of values, see [3].
// [1] https://groups.google.com/a/groups.riscv.org/g/sw-dev/c/QKjUDjz_vKo
// [2] https://github.com/riscv/riscv-isa-manual/blob/main/marchid.md
// [3] https://five-embeddev.com/riscv-priv-isa-manual/Priv-v1.12/machine.html#machine-architecture-id-register-marchid
struct riscv_cpuinfo *get_riscv_cpuinfo(void) {
struct riscv_cpuinfo* ci = emalloc(sizeof(struct riscv_cpuinfo));
ci->mvendorid = parse_cpuinfo_field_uint64(CPUINFO_RISCV_MVENDORID);
ci->marchid = parse_cpuinfo_field_uint64(CPUINFO_RISCV_MARCHID);
ci->mimpid = parse_cpuinfo_field_uint64(CPUINFO_RISCV_MIMPID);
if (ci->mvendorid == 0 && ci->mvendorid == 0 && ci->mvendorid == 0)
return NULL;
return ci;
}
char* get_hardware_from_devtree(void) {
return get_field_from_devtree(DEVTREE_HARDWARE_FIELD);
}

View File

@@ -5,8 +5,16 @@
#define UNKNOWN -1
// https://elixir.bootlin.com/linux/v6.10.6/source/arch/riscv/include/asm/cpufeature.h#L21
struct riscv_cpuinfo {
unsigned long mvendorid;
unsigned long marchid;
unsigned long mimpid;
};
char* get_hardware_from_devtree(void);
char* get_uarch_from_cpuinfo(void);
char* get_extensions_from_cpuinfo(void);
struct riscv_cpuinfo *get_riscv_cpuinfo(void);
#endif

View File

@@ -333,6 +333,15 @@ struct features* get_features_info(struct cpuInfo* cpu) {
bool hv_present = (ecx & (1U << 31)) != 0;
if((cpu->hv = get_hp_info(hv_present)) == NULL)
return NULL;
if(cpu->hv->present) {
// Hypervisor will likely mess up something and users will think that
// there is something wrong with cpufetch whereas actually cpufetch has
// nothing to do with it.
// https://github.com/Dr-Noob/cpufetch/issues/96
// https://github.com/Dr-Noob/cpufetch/issues/267
// https://github.com/Dr-Noob/cpufetch/issues/293
printWarn("You are running an hypervisor. Please note that it will likely tamper your results, so do not post an issue if you find anything incorrect");
}
}
else {
printWarn("Can't read features information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000001, cpu->maxLevels);

View File

@@ -255,7 +255,7 @@ struct uarch* get_uarch_from_cpuid_intel(uint32_t ef, uint32_t f, uint32_t em, u
// CHECK_UARCH(arch, 0, 6, 8, 14, 9, ...) It is not possible to determine uarch only from CPUID dump (can be Kaby Lake or Amber Lake)
// CHECK_UARCH(arch, 0, 6, 8, 14, 10, ...) It is not possible to determine uarch only from CPUID dump (can be Kaby Lake R or Coffee Lake U)
CHECK_UARCH(arch, 0, 6, 8, 14, 11, "Whiskey Lake", UARCH_WHISKEY_LAKE, 14) // wikichip
CHECK_UARCH(arch, 0, 6, 8, 14, 12, "Comet Lake", UARCH_COMET_LAKE, 14) // wikichip
// CHECK_UARCH(arch, 0, 6, 8, 14, 12, ...) It is not possible to determine uarch only from CPUID dump (can be Comet Lake U or Whiskey Lake U)
CHECK_UARCH(arch, 0, 6, 8, 15, 8, "Sapphire Rapids", UARCH_SAPPHIRE_RAPIDS, 7) // wikichip
CHECK_UARCH(arch, 0, 6, 9, 6, NA, "Tremont", UARCH_TREMONT, 10) // LX*
CHECK_UARCH(arch, 0, 6, 9, 7, NA, "Alder Lake", UARCH_ALDER_LAKE, 10) // instlatx64 (Alder Lake-S)
@@ -447,6 +447,7 @@ struct uarch* get_uarch_from_cpuid_hygon(uint32_t ef, uint32_t f, uint32_t em, u
struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t dump, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
if(cpu->cpu_vendor == CPU_VENDOR_INTEL) {
struct uarch* arch = emalloc(sizeof(struct uarch));
// TODO: Refactor these 3 checks in a common function.
if(dump == 0x000806E9) {
if (cpu->cpu_name == NULL) {
printErr("Unable to find uarch without CPU name");
@@ -486,6 +487,30 @@ struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t dump, uint32_t
return arch;
}
else if (dump == 0x000806EC) {
if (cpu->cpu_name == NULL) {
printErr("Unable to find uarch without CPU name");
fill_uarch(arch, STRING_UNKNOWN, UARCH_UNKNOWN, UNK);
return arch;
}
// It is not possible to determine uarch only from CPUID dump (can be Comet Lake U or Whiskey Lake U)
// https://github.com/Dr-Noob/cpufetch/issues/298
if (strstr(cpu->cpu_name, "i3-8145U") != NULL ||
strstr(cpu->cpu_name, "i5-8265U") != NULL ||
strstr(cpu->cpu_name, "i5-8365U") != NULL ||
strstr(cpu->cpu_name, "i7-8565U") != NULL ||
strstr(cpu->cpu_name, "i7-8665U") != NULL ||
strstr(cpu->cpu_name, "5405U") != NULL ||
strstr(cpu->cpu_name, "4205U") != NULL) {
fill_uarch(arch, "Whiskey Lake", UARCH_WHISKEY_LAKE, 14);
}
else {
fill_uarch(arch, "Comet Lake", UARCH_COMET_LAKE, 14);
}
return arch;
}
return get_uarch_from_cpuid_intel(ef, f, em, m, s);
}
else if(cpu->cpu_vendor == CPU_VENDOR_AMD) {