我正在尝试使用宏函数读取 csr 寄存器
我有一个结构数组,其中包含 csr 寄存器的名称和地址
typedef struct csr_lists
{
int address;
const cahr* name;
} csr_lists;
csr_lists list[] =
{
{0xc00, "CYCLE"},
...
};
还有我做的功能:
#define csr_read(csr) \
({ \
register uint32_t v; \
__asm__ __volatile__ ("csrr %0, %1" \
: "=r" (v) \
: "n" (csr) \
: "memory"); \
v; \
})
所以它被称为
uint64_t value = csr_read(list[i].address);
或uint64_t value = csr_read(0xc00);
编译器给我以下错误
csr.h:68:2: error: asm operand 1 probably doesn’t match constraints [-Werror]
68 | __asm__ __volatile__ ("csrr %0, %1" \
| ^~~~~~~
csr.c:127:25: note: in expansion of macro ‘csr_read’
127 | value[i] = csr_read(list[i].address);
|
csr.h:68:2: error: impossible constraint in ‘asm’
68 | __asm__ __volatile__ ("csrr %0, %1" \
| ^~~~~~~
csr.c:127:25: note: in expansion of macro ‘csr_read’
127 | value[i] = csr_read(list[i].address);
|
cc1: all warnings being treated as errors
/mnt/d/project/riscv32-linux/buildroot-2021.02.10/output/host/lib/gcc/riscv32-buildroot-linux-gnu/9.4.0/../../../../riscv32-buildroot-linux-gnu/bin/ld: ./libhpm.so: undefined reference to `csr_read'
我该如何解决这个问题?
编辑) 问题发生在这些行
#define MAX 7
for (i = 0; i < MAX; i++)
{
value[i] = csr_read(list[i].address);
}
也许这个片段会对下一个看这个的人有所帮助。
我相信原来的问题现在已经很好地解决了。 主要问题是你必须为'csr'值使用编译时常量,你不能使用寄存器/变量来提供这个。这意味着你不能把它放在一个循环中并从中获取CSR寄存器号C中的一个变量。
生成的特定 ASM 指令被编码为包含 CSR 寄存器编号,要使用的 CSR 永远不会从通用寄存器中获取,它被编码到指令本身中。
只有从写入到读取的值(CSR 寄存器的内容)始终使用通用寄存器。允许从 C 中的变量中获取或返回值。
另一件事是在问题中使用
"memory"
clobber约束可能不是你想要的。这指示编译器在 CSR 访问周围执行屏障,但这与 CSR 访问指令没有副作用会以编译器不期望的方式改变内存的一般声明(我在这里提出)相矛盾。把它想象成一个 IO 设备,你改变的是硬件状态而不是内存状态。
大多数使用 CSR 指令的用户空间从不需要内存屏障,如定时器/计数器/FPU 状态,这样做将导致编译器生成不太优化的代码。由于过多的失效和内存状态的重新加载。
在某些特定情况下,CSR 访问确实需要屏障,但它们是例外情况,您应该使用单独的 C 语言语句显式执行。而不是降低具有许多用例的宏基元的性能。
宏包含使用信息,因为编译器有助于为代码提供编译错误消息,这将提醒用户这种特殊的用法。
#define CSRR_READ(v, csr) \
/* CSRR_READ(v, csr):
* csr: MUST be a compile time integer 12-bit constant (0-4095)
*/ \
__asm__ __volatile__ ("csrr %0, %1" \
: "=r" (v) \
: "n" (csr) \
: /* clobbers: none */ );