RISC-V 體系結構編程與實踐

奔跑吧Linux社區

  • RISC-V 體系結構編程與實踐-preview-1
  • RISC-V 體系結構編程與實踐-preview-2
RISC-V 體系結構編程與實踐-preview-1

買這商品的人也買了...

相關主題

商品描述

本書旨在介紹RISC-V體系結構的設計和實現。本書首先介紹RISC-V體系結構的基礎知識、實驗環境搭建、常用指令、函數調用規範與棧,然後講述GNU匯編器、鏈接器、鏈接腳本和GCC內嵌匯編代碼,接著討論RISC-V體系結構中的異常處理、中斷、內存管理、高速緩存、緩存一致性、TLB管理、原子操作、內存屏障指令,最後闡述RSIC-V體系結構中的壓縮指令擴展、虛擬化擴展等。

本書不僅適合軟件開發人員閱讀,還可以作為電腦相關專業和相關培訓機構的教材。

作者簡介

作者简介

奔跑吧Linux社区 由一群热爱开源的工程师组成,致力于开源硬件和开源软件的推广。

 

 

审校者简介

 

 

香山处理器团队

面向世界的体系结构创新开源平台,目前已形成由多家企业组成的香山联合开发团队。其中,香山处理器是由中国科学院计算技术研究所发起的开源高性能RISC-V处理器核项目。

 

 

龙蜥社区RISC-V SIG

坚持开放、开源,致力于龙蜥社区以及 RISCV 软硬件生态的共建和推广。

 

 

进迭时空

专注研发新一代高性能RISC-V处理器和计算系统,让开发者基于RISC-V芯片更自由地开发更有创意的新应用。

目錄大綱

 

目  錄

 

 

 

第 1章 RISC-V體系結構基礎知識 1

1.1 RISC-V介紹 1

1.1.1 RISC-V指令集優點 1

1.1.2 RISC-V指令集擴展 2

1.1.3 RISC-V商業化發展 2

1.2 RISC-V體系結構介紹 3

1.2.1 RISC-V體系結構 3

1.2.2 採用RISC-V體系結構的常見處理器 3

1.2.3 RISC-V體系結構中的基本概念 4

1.2.4 SBI服務 5

1.3 RISC-V寄存器 6

1.3.1 通用寄存器 6

1.3.2 系統寄存器 7

1.3.3 U模式下的系統寄存器 8

1.3.4 S模式下的系統寄存器 9

1.3.5 M模式下的系統寄存器 11

1.4 香山處理器介紹 15

1.4.1 香山處理器體系結構 15

1.4.2 香山處理器的前端子系統 16

1.4.3 香山處理器的後端子系統 18

1.4.4 香山處理器的訪存子系統 20

1.4.5 香山處理器的L2/L3高速緩存 25

 

第 2章 搭建RISC-V實驗環境 29

2.1 實驗平臺 29

2.1.1 QEMU 29

2.1.2 NEMU 30

2.2 搭建實驗環境 31

2.2.1 實驗2-1:輸出“Welcome RISC-V!” 31

2.2.2 實驗2-2:單步調試BenOS和MySBI 32

2.3 BenOS和MySBI基礎實驗代碼解析 34

2.3.1 MySBI基礎代碼分析 34

2.3.2 BenOS基礎代碼分析 37

2.3.3 合並BenOS和MySBI 41

2.4 QEMU + RISC-V + Linux實驗平臺 41

 

 

第3章 基礎指令集 44

3.1 RISC-V指令集介紹 44

3.2 RISC-V指令編碼格式 45

3.3 加載與存儲指令 46

3.4 PC相對尋址 49

3.5 移位操作 53

3.6 位操作指令 55

3.7 算術指令 56

3.8 比較指令 57

3.9 無條件跳轉指令 58

3.10 條件跳轉指令 59

3.11 CSR指令 61

3.12 尋址範圍 62

3.13 陷阱:為什麽ret之後就進入死循環 62

3.14 實驗 64

3.14.1 實驗3-1:熟悉加載指令 64

3.14.2 實驗3-2:PC相對地址尋址 64

3.14.3 實驗3-3:memcpy()函數的實現 65

3.14.4 實驗3-4:memset()函數的實現 65

3.14.5 實驗3-5:條件跳轉指令1 65

3.14.6 實驗3-6:條件跳轉指令2 66

3.14.7 實驗3-7:子函數跳轉 66

3.14.8 實驗3-8:在匯編中實現串口輸出功能 66

 

第4章 函數調用規範與棧 67

4.1 函數調用規範 67

4.2 入棧與出棧 70

4.3 RISC-V棧的佈局 72

4.3.1 不使用FP的棧佈局 72

4.3.2 使用FP的棧佈局 74

4.3.3 棧回溯 76

4.4 實驗 78

4.4.1 實驗4-1:觀察棧佈局 78

4.4.2 實驗4-2:觀察棧回溯 78

 

第5章 GNU匯編器 79

5.1 編譯流程與ELF文件 79

5.2 一個簡單的匯編程序 82

5.3 匯編語法 84

5.3.1 註釋 84

5.3.2 符號 84

5.4 常用的偽指令 85

5.4.1 對齊偽指令 85

5.4.2 數據定義偽指令 86

5.4.3 與函數相關的偽指令 87

5.4.4 與段相關的偽指令 87

5.4.5 與宏相關的偽指令 89

5.4.6 與文件相關的偽指令 91

5.5 RISC-V依賴特性 91

5.5.1 RISC-V特有的命令行選項 91

5.5.2 RISC-V特有的偽指令 92

5.6 實驗 92

5.6.1 實驗5-1:匯編語言練習—查找最大數 92

5.6.2 實驗5-2:匯編語言練習—通過C語言調用匯編函數 92

5.6.3 實驗5-3:匯編語言練習—通過匯編語言調用C函數 92

5.6.4 實驗5-4:使用匯編偽操作實現一張表 92

5.6.5 實驗5-5:匯編宏的使用 93

 

第6章 鏈接器與鏈接腳本 94

6.1 鏈接器 94

6.2 鏈接腳本 95

6.2.1 一個簡單的鏈接程序 95

6.2.2 設置入口點 96

6.2.3 基本概念 97

6.2.4 符號賦值與引用 97

6.2.5 當前位置計數器 98

6.2.6 SECTIONS命令 99

6.2.7 常用的內置函數 101

6.3 加載重定位 103

6.3.1 BenOS重定位 103

6.3.2 OpenSBI和Linux內核重定位 105

6.4 鏈接重定位與鏈接器鬆弛優化 108

6.4.1 鏈接重定位 108

6.4.2 函數跳轉優化 112

6.4.3 符號地址訪問優化 114

6.5 實驗 116

6.5.1 實驗6-1:分析鏈接腳本 116

6.5.2 實驗6-2:輸出每個段的內存佈局 116

6.5.3 實驗6-3:加載地址不等於運行地址 117

6.5.4 實驗6-4:設置鏈接地址 117

6.5.5 實驗6-5:鏈接器鬆弛優化1 117

6.5.6 實驗6-6:鏈接器鬆弛優化2 117

6.5.7 實驗6-7:分析Linux 5.15內核的鏈接腳本 117

 

 

第7章 內嵌匯編代碼 118

7.1 內嵌匯編代碼基本用法 118

7.1.1 基礎內嵌匯編代碼 118

7.1.2 擴展內嵌匯編代碼 118

7.1.3 內嵌匯編代碼修飾符 120

7.1.4 使用匯編符號名字 121

7.1.5 內嵌匯編代碼與宏結合 122

7.1.6 使用goto修飾詞 122

7.1.7 小結 123

7.2 案例分析 124

7.3 註意事項 128

7.4 實驗 128

7.4.1 實驗7-1:實現簡單的memcpy()函數 128

7.4.2 實驗7-2:使用匯編符號名寫內嵌匯編代碼 128

7.4.3 實驗7-3:使用內嵌匯編代碼完善memset()函數 129

7.4.4 實驗7-4:使用內嵌匯編代碼與宏的結合 129

7.4.5 實驗7-5:實現讀和寫系統寄存器的宏 129

7.4.6 實驗7-6:goto模板的內嵌匯編代碼 129

 

 

第8章 異常處理 130

8.1 異常處理基本概念 130

8.1.1 異常類型 130

8.1.2 同步異常和異步異常 131

8.1.3 異常入口和返回 131

8.1.4 異常返回地址 132

8.1.5 異常返回的處理器模式 133

8.1.6 棧的選擇 133

8.2 與M模式相關的異常寄存器 133

8.2.1 mstatus寄存器 134

8.2.2 mtvec寄存器 134

8.2.3 mcause寄存器 135

8.2.4 mie寄存器 135

8.2.5 mtval寄存器 136

8.2.6 mip寄存器 136

8.2.7 mideleg和medeleg寄存器 136

8.2.8 中斷配置 137

8.3 與S模式相關的異常寄存器 137

8.3.1 sstatus寄存器 137

8.3.2 sie寄存器 137

8.3.3 sip寄存器 138

8.3.4 scause寄存器 138

8.3.5 stvec寄存器 138

8.3.6 stval寄存器 139

8.4 異常上下文 139

8.4.1 保存異常上下文 141

8.4.2 恢復異常上下文 141

8.5 案例分析8-1:實現SBI系統調用 142

8.5.1 調用ECALL指令 142

8.5.2 實現SBI系統調用 143

8.6 案例分析8-2:BenOS的異常處理 148

8.6.1 設置異常向量表 148

8.6.2 保存和恢復異常上下文 149

8.6.3 異常處理 151

8.6.4 委托中斷和異常 153

8.6.5 觸發異常 153

8.7 實驗 154

8.7.1 實驗8-1:在SBI中實現串口輸入功能 154

8.7.2 實驗8-2:在BenOS中觸發非法指令異常 155

8.7.3 實驗8-3:輸出觸發異常時函數棧的調用過程 155

8.7.4 實驗8-4:在MySBI中模擬實現RDTIME偽指令 155

 

第9章 中斷處理與中斷控制器 156

9.1 中斷處理基本概念 156

9.1.1 中斷類型 156

9.1.2 中斷處理過程 157

9.1.3 中斷委派和註入 158

9.1.4 中斷優先級 158

9.2 CLINT 159

9.3 案例分析9-1:定時器中斷 160

9.3.1 訪問mtimer 160

9.3.2 在MySBI中實現定時器服務 160

9.3.3 定時器中斷處理 161

9.3.4 打開中斷總開關 163

9.3.5 小結 164

9.4 PLIC 164

9.4.1 中斷號 165

9.4.2 中斷優先級 166

9.4.3 中斷使能寄存器 166

9.4.4 中斷待定寄存器 166

9.4.5 中斷優先級閾值寄存器 167

9.4.6 中斷請求/完成寄存器 167

9.5 案例分析9-2:串口中斷 167

9.5.1 初始化PLIC 168

9.5.2 使能串口0的接收中斷 169

9.5.3 處理中斷 169

9.6 實驗 171

9.6.1 實驗9-1:定時器中斷 171

9.6.2 實驗9-2:使用匯編函數保存和恢復中斷現場 171

9.6.3 實驗9-3:實現並調試串口0中斷 171

 

 

第 10章 內存管理 172

10.1 內存管理基礎知識 172

10.1.1 內存管理的“遠古時代” 172

10.1.2 地址空間的抽象 174

10.1.3 分段機制 175

10.1.4 分頁機制 175

10.2 RISC-V內存管理 178

10.2.1 頁表分類 179

10.2.2 Sv39頁表映射 180

10.2.3 Sv48頁表映射 182

10.2.4 頁表項描述符 183

10.2.5 頁表屬性 185

10.2.6 與地址轉換相關的寄存器 186

10.3 物理內存屬性與物理內存保護 187

10.3.1 物理內存屬性 187

10.3.2 物理內存保護 188

10.4 案例分析10-1:在BenOS里實現恆等映射 190

10.4.1 頁表定義 191

10.4.2 頁表數據結構 193

10.4.3 創建頁表 193

10.4.4 打開MMU 198

10.4.5 測試MMU 198

10.4.6 圖解頁表創建的過程 200

10.5 內存管理實驗 204

10.5.1 實驗10-1:建立恆等映射 204

10.5.2 實驗10-2:為什麽MMU無法運行 205

10.5.3 實驗10-3:實現一個MMU頁表的轉儲功能 205

10.5.4 實驗10-4:修改頁面屬性 205

10.5.5 實驗10-5:使用匯編語言來建立恆等映射 206

10.5.6 實驗10-6:在MySBI中實現和驗證PMP機制 206

 

 

第 11章 高速緩存 207

11.1 為什麽需要高速緩存 207

11.2 高速緩存的訪問延時 208

11.3 高速緩存的工作原理 210

11.4 高速緩存的映射方式 212

11.4.1 直接映射 212

11.4.2 全相聯映射 213

11.4.3 組相聯映射 213

11.4.4 組相聯的高速緩存的例子 214

11.5 虛擬高速緩存與物理高速緩存 215

11.5.1 物理高速緩存 215

11.5.2 虛擬高速緩存 215

11.5.3 VIPT和PIPT 215

11.6 重名和同名問題 216

11.6.1 重名問題 217

11.6.2 同名問題 217

11.6.3 VIPT產生的重名問題 218

11.7 高速緩存策略 220

11.8 高速緩存的維護指令 221

11.8.1 高速緩存管理指令 221

11.8.2 高速緩存預取指令 222

 

 

第 12章 緩存一致性 224

12.1 為什麽需要緩存一致性 224

12.2 緩存一致性的分類 225

12.2.1 緩存一致性協議發展歷程 225

12.2.2 緩存一致性分類 226

12.2.3 系統緩存一致性問題 227

12.3 緩存一致性的解決方案 227

12.3.1 關閉高速緩存 228

12.3.2 使用軟件維護緩存一致性 228

12.3.3 使用硬件維護緩存一致性 228

12.4 MESI協議 228

12.4.1 MESI協議簡介 229

12.4.2 本地讀寫與總線操作 230

12.4.3 MESI狀態轉換 230

12.4.4 初始狀態為I 231

12.4.5 初始狀態為M 233

12.4.6 初始狀態為S 234

12.4.7 初始狀態為E 234

12.4.8 小結與案例分析 235

12.4.9 MOESI協議 237

12.5 高速緩存偽共享 237

12.6 兩種緩存一致性控制器 239

12.6.1 CCI緩存一致性控制器 239

12.6.2 CCN緩存一致性控制器 240

12.7 案例分析12-1:偽共享的避免 241

12.8 案例分析12-2:DMA和高速緩存的一致性 242

12.8.1 從內存到設備的FIFO緩沖區 243

12.8.2 從設備的FIFO緩沖區到內存 243

12.9 案例分析12-3:自修改代碼的一致性 244

12.10 實驗 245

12.10.1 實驗12-1:高速緩存偽共享 245

12.10.2 實驗12-2:使用Perf C2C發現高速緩存偽共享 245

 

 

第 13章 TLB管理 246

13.1 TLB基礎知識 247

13.2 TLB重名與同名問題 249

13.2.1 重名問題 249

13.2.2 同名問題 250

13.3 ASID 251

13.4 TLB管理指令 253

13.4.1 TLB維護指令介紹 253

13.4.2 TLB廣播 254

13.4.3 SFENCE.VMA指令使用場景 256

13.5 TLB案例分析 256

13.5.1 TLB在Linux內核中的應用 256

13.5.2 ASID在Linux內核中的應用 257

13.5.3 Linux內核中的TLB維護操作 257

13.5.4 BBM機制 259

 

 

第 14章 原子操作 261

14.1 原子操作介紹 261

14.2 保留加載與條件存儲指令 262

14.3 獨占內存訪問工作原理 263

14.3.1 獨占監視器 264

14.3.2 獨占監視器與緩存一致性 265

14.4 原子內存訪問操作指令 266

14.4.1 原子內存訪問指令工作原理 266

14.4.2 原子內存訪問指令與LR/SC指令的效率對比 267

14.4.3 RISC-V中的原子內存訪問指令 268

14.5 比較並交換操作 270

 

 

第 15章 內存屏障指令 275

15.1 內存屏障指令產生的原因 275

15.1.1 順序一致性內存模型 276

15.1.2 處理器一致性內存模型 277

15.1.3 弱一致性內存模型 277

15.1.4 釋放一致性內存模型 278

15.1.5 MCA模型 279

15.2 RISC-V約束條件 280

15.2.1 全局內存次序與保留程序次序 280

15.2.2 RVWMO的約束規則 281

15.3 RISC-V中的內存屏障指令 284

15.3.1 使用內存屏障的場景 284

15.3.2 FENCE指令 285

15.3.3 內置獲取和釋放屏障原語的指令 285

15.3.4 FENCE.I指令 286

15.3.5 SFENCE.VMA指令 286

15.4 RISC-V內存屏障指令移植指南 286

15.4.1 從RISC-V到x86體系結構 286

15.4.2 從RISC-V到ARM體系結構 287

15.4.3 Linux內核常用的內存屏障API函數 287

15.5 案例分析 288

15.5.1 消息傳遞問題 288

15.5.2 單方向內存屏障與自旋鎖 289

15.5.3 郵箱傳遞消息 290

15.5.4 關於DMA的案例 291

15.5.5 在Linux內核中使指令高速緩存失效 291

15.6 模擬和測試內存屏障故障 291

15.6.1 使用Litmus測試工具集 292

15.6.2 編寫C程序來模擬 295

15.7 實驗 297

15.7.1 實驗15-1:編寫Litmus腳本並測試內存一致性1 297

15.7.2 實驗15-2:編寫Litmus腳本並測試內存一致性2 298

 

 

第 16章 合理使用內存屏障指令 299

16.1 存儲緩沖區與寫內存屏障指令 300

16.2 無效隊列與讀內存屏障指令 305

16.3 內存屏障指令總結 307

16.4 案例分析:Linux內核中的內存屏障指令 308

16.4.1 第 一次使用內存屏障指令 309

16.4.2 第二次使用內存屏障指令 310

16.4.3 第三次使用內存屏障指令 313

16.4.4 第四次使用內存屏障指令 314

16.4.5 小結:內存屏障指令的使用 315

16.5 實驗 315

16.5.1 實驗16-1:驗證和測試內存一致性1 315

16.5.2 實驗16-2:驗證和測試內存一致性2 315

16.5.3 實驗16-3:驗證和測試內存一致性3 315

 

 

第 17章 與操作系統相關的內容 316

17.1 C語言常見陷阱 317

17.1.1 數據模型 317

17.1.2 數據類型轉換與整型提升 318

17.1.3 移位操作 320

17.2 創建進程 320

17.2.1 進程控制塊 320

17.2.2 0號進程 321

17.2.3 do_fork()函數的實現 323

17.2.4 進程上下文切換 324

17.2.5 新進程的第 一次執行 326

17.3 簡易進程調度器 327

17.3.1 擴展進程控制塊 327

17.3.2 就緒隊列 327

17.3.3 調度類 328

17.3.4 簡易調度器的實現 329

17.3.5 自願調度 330

17.3.6 搶占調度 331

17.3.7 測試用例 333

17.3.8 關於調度的思考 333

17.4 讓進程運行在用戶模式 335

17.5 系統調用 338

17.5.1 系統調用介紹 338

17.5.2 在用戶模式下調用SVC指令 338

17.5.3 在內核模式下對系統調用的處理 339

17.5.4 系統調用表 340

17.6 實現clone系統調用 341

17.7 實驗 343

17.7.1 實驗17-1:進程創建 343

17.7.2 實驗17-2:進程調度 343

17.7.3 實驗17-3:讓進程運行在用戶模式 343

17.7.4 實驗17-4:新增一個malloc()系統調用 343

17.7.5 實驗17-5:新增一個clone()系統調用 344

 

 

第 18章 可伸縮矢量計算與優化 345

18.1 矢量計算基本概念 345

18.1.1 SISD與SIMD 345

18.1.2 定長計算與可變長矢量計算 347

18.1.3 通道 347

18.1.4 矢量與標量 347

18.2 RVV寄存器 348

18.2.1 矢量寄存器 348

18.2.2 mstatus寄存器中的矢量上下文狀態 348

18.2.3 vtype寄存器 348

18.2.4 vl寄存器 350

18.2.5 vlenb寄存器 351

18.2.6 vstart寄存器 351

18.3 配置編譯和運行環境 351

18.3.1 搭建編譯環境 351

18.3.2 運行第 一個“hello RVV!”程序 352

18.3.3 單步調試匯編程序 353

18.3.4 單步調試C語言與匯編混合程序 355

18.4 RVV指令格式 357

18.5 配置指令 358

18.6 加載和存儲指令 360

18.6.1 單位步長模式 360

18.6.2 任意步長模式 363

18.6.3 聚合加載/離散存儲 364

18.6.4 打包數據的加載與存儲 365

18.6.5 首次異常加載指令 367

18.6.6 加載和存儲全部矢量數據 368

18.7 矢量掩碼指令 369

18.7.1 邏輯操作指令 369

18.7.2 VCPOP.M指令 369

18.7.3 VFIRST.M指令 370

18.7.4 VMSBF.M指令 370

18.7.5 VMSIF.M指令 371

18.7.6 VMSOF.M指令 372

18.8 矢量整型算術指令 372

18.8.1 加寬和變窄算術指令 372

18.8.2 加法和減法指令 373

18.8.3 加寬模式的加法和減法指令 374

18.8.4 位操作指令 376

18.8.5 移位操作指令 376

18.8.6 比較指令 376

18.8.7 數據搬移指令 377

18.9 案例分析18-1:使用RVV指令優化strcmp()函數 377

18.9.1 使用純匯編方式 378

18.9.2 測試 379

18.10 案例分析18-2:RGB24轉BGR24 380

18.10.1 使用C語言實現RGB24轉BGR24 380

18.10.2 使用RVV指令優化 380

18.10.3 測試 381

18.11 案例分析18-3:4 × 4矩陣乘法運算 382

18.11.1 使用C語言實現4 × 4矩陣乘法運算 382

18.11.2 使用RVV指令優化 383

18.11.3 測試 387

18.12 案例分析18-4:使用RVV內置函數 388

18.13 案例分析18-5:自動矢量優化 388

18.14 術語 390

18.15 實驗 391

18.15.1 實驗18-1:RGB24轉BGR32 391

18.15.2 實驗18-2:8 × 8矩陣乘法運算 391

18.15.3 實驗18-3:使用RVV指令優化strcpy()函數 391

18.15.4 實驗18-4:使用RVV內置函數優化 391

18.15.5 實驗18-5:使用RVV優化轉置矩陣的求法 392

 

 

第 19章 壓縮指令擴展 393

19.1 RISC-V指令集的特點 393

19.2 RVC支持的指令格式與指令編碼 394

 

第 20章 虛擬化擴展 396

20.1 虛擬化技術介紹 396

20.1.1 虛擬化技術的發展歷史 396

20.1.2 虛擬機管理程序的分類 398

20.1.3 內存虛擬化 398

20.1.4 I/O虛擬化 399

20.2 RISC-V虛擬化擴展 399

20.2.1 CPU虛擬化擴展 399

20.2.2 M模式下系統寄存器的擴展 400

20.2.3 HS模式下的系統寄存器 402

20.2.4 VS模式下的系統寄存器 404

20.3 RISC-V內存虛擬化 404

20.4 RISC-V虛擬化擴展中的新增指令 406

20.4.1 加載與存儲虛擬機內存指令 406

20.4.2 虛擬化內存屏障指令 406

20.5 進入和退出虛擬機 407

20.5.1 異常陷入 408

20.5.2 異常返回 408

20.5.3 新增的中斷與異常類型 409

20.6 中斷虛擬化 410

20.6.1 虛擬中斷註入 410

20.6.2 陷入與模擬 411

20.7 案例分析20-1:進入和退出虛擬機 412

20.7.1 進入虛擬機 413

20.7.2 退出虛擬機 414

20.8 案例分析20-2:建立虛擬化兩階段地址映射 415

20.8.1 建立第二階段的地址映射 416

20.8.2 建立第 一階段的地址映射 418

20.8.3 測試 419

20.9 案例分析20-3:在虛擬機中實現虛擬定時器 420

20.10 案例分析20-4:在VMM中加載和存儲虛擬機內存地址 422

20.11 案例分析20-5:在VMM中模擬串口設備 424

20.12 實驗 429

20.12.1 實驗20-1:加載虛擬機1 429

20.12.2 實驗20-2:加載虛擬機2 430

20.12.3 實驗20-3:虛擬化地址映射 430

20.12.4 實驗20-4:解析虛擬機陷入的指令 430

20.12.5 實驗20-5:在VMM中模擬實現vPLIC 430

20.12.6 實驗20-6:在虛擬機中加載並運行Linux內核 430

附錄A 關於RISC-V體系結構自測題的參考答案與提示 431

附錄B RV64I指令速查表 433

附錄C RV64M指令速查表 437

附錄D RV64常用偽指令速查表 439