鐵人賽
今天我們來聊聊該如何使用這些 CSR 指令呢,前些日子裡我們已經有介紹許多 CSR 了,可以先觀看 DAY2 以及 DAY3 的文章唷,介紹了許多 CSR,有些是只能讀,有些只能寫,有些可以讀以及寫,根據該 CSR 定義的不同,則有所不同,以下我們正式介紹。
事實上 Linux kernel 有提供我們相關 Macro 可以方便我們使用
/* csr.h */
#define csr_read(reg) ({ unsigned long __tmp; \
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
#define csr_write(reg, val) ({ \
asm volatile ("csrw " #reg ", %0" :: "rK"(val)); })
#define csr_set(reg, bit) ({ unsigned long __tmp; \
asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \
__tmp; })
#define csr_clear(reg, bit) ({ unsigned long __tmp; \
asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \
__tmp; })
#define csr_swap(reg, val) ({ \
unsigned long __v = (unsigned long)(val); \
asm volatile ("csrrw %0, " #reg ", %1" : "=r" (__v) : "rK" (__v) : "memory"); \
__v; })
根據 kernel 的 csr.h
文件當中一共有五個 macro 讓我們來操作這些 CSR,根據觀察這些 macro ,可以發現他們是由 assembly 的方式實作的,因此有需要時,也可以直接使用 csr*
指令的方式進行 CSR 的操作。
接下來我們將細部說明各個 csr*
指令
CSRRW(Atomic Read/Write CSR):CSRRW 讀取當前 CSR 中的值,將其補零擴展到 XLEN 位,然後寫到 rd
中,再將 rs1
中的值將被寫入 CSR 中。
csrrw a0, misa,zero
a0
是rd
,zero 是rs1
,misa
(machine ISA register)是 CSR,
因此,讀取misa
的值將其放進a0,最後將 zero 的值寫入到misa
CSRRS (Atomic Read and Set Bit in CSR) :CSRRS 讀取當前 CSR 中的值,寫到 rd
中,再將 rs1
的值對應第幾位 bit 為1的寫入 CSR 當中的對應 bit 將其設為1(很饒口嗎,看例子好懂)
li a1,0X3
csrrs a0, mie, a1
a1
為 0x3(二進制來觀察就是 0011)a0
是rd
,a1
是rs1
,mie
(machine interrupt enable)是CSR,
因此,讀取mie
的值寫到a0
,接著將a1
當中對應 bit 為1的,寫到mie
,因此mie
的 bit 0 以及 bit 1 皆被設為1了,再一個例子。
li a1, 0x5
csrrs a0, mie, a1
a1
為0x5(二進制來觀察就是 0101)
一樣讀取mie
的值寫到a0
,接著a1
當中對應 bit 為1的寫到mie
,因此mie
的bit 0以及bit 2皆被設為1了
CSRRC(Atomic Read and Clear Bit in CSR):rs1 中對應bit為 1 的位,將導致 CSR 中對應位被清0,這跟前一個類似,應該說剛好相反吧,總之看例子較好理解
li a1,0x3
csrrc a0, mie,a1
a0
是rd
,a1
是rs1
,mie
(machine interrupt enable)是CSR,因此,讀取mie
的值寫到a0
,接著將a1
當中對應bit為1的,對應到mie
並清0,因此mie
的bit0以及bit1皆被設為0了
CSRRWI
csrrwi zero,mstatus,1
只寫1到mstatus中,不讀取csr
CSRRSI
csrrsi zero,mstatus,0x02
只設置bit 1(因為0x2二進制就是 0010)數值為1,不讀csr
今日我們介紹了許多 CSR 的用法,通常直接使用 macro 會是比較平易近人的作法,但也不排除可能會需要用到 assembly 的方式,因此這邊也作一些介紹,明天來說明如何使用 sbi_ecall。