使用 C asm 读取 RISC-V CSR 寄存器

问题描述 投票:0回答:1

我正在尝试使用宏函数读取 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 doesnt 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);
}
assembly gcc inline-assembly riscv
1个回答
0
投票

也许这个片段会对下一个看这个的人有所帮助。

我相信原来的问题现在已经很好地解决了。 主要问题是你必须为'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 */ );
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.