網(wǎng)站首頁 編程語言 正文
SOC驗證環(huán)境一千家公司有一千家公司的做法。那么一個優(yōu)秀的SOC驗證環(huán)境應(yīng)該具備哪些功能呢?
首先是SOC驗證環(huán)境支持C和SV兩種下激勵的方式。
通過C code啟動SOC環(huán)境是怎么啟動的呢?這里涉及到CPU如何boot,對此很多轉(zhuǎn)行的同學可能很難理解,在這里和大家做個簡單的介紹。
我們知道CPU執(zhí)行的是指令和數(shù)據(jù),馮諾依曼結(jié)構(gòu)是將指令和數(shù)據(jù)合并在一起存儲,如8086。
哈弗結(jié)構(gòu)是將指令和數(shù)據(jù)分開存儲,如ARM系列。
無論是哪種結(jié)構(gòu)CPU都是通過指令實現(xiàn)程序跳轉(zhuǎn)或者數(shù)據(jù)讀寫。什么是指令?以RISCV為例,其指令格式如下
我們以簡單的加法運算為例,比如我想做一個 rd= rs1+rs2 這樣一個寄存器加法運算,偽代碼就是 add rd,rs1,rs2 。通過上述RISCV的指令格式應(yīng)該就是
funct7,funct3,opcode又是什么呢?通過查詢 riscv 手冊可以查到以下結(jié)果。
由此我們組成一個簡單的加法的操作指令,CPU拿到這個操作指令之后就可以進行寄存器的加法運算。
事實上除了上述的寄存器操作指令,CPU還支持其他控制指令和數(shù)據(jù)處理指令。以riscv的標準指令集為例,其分別有以下6種類型。
R-format for register-register arithmetic/logical operations
I-format for register-immediate arith/logical operations and loads
S-format for stores
B-format for branches
U-format for 20-bit upper immediate instructions
J-format for jumps
大部分我們SOC對寄存器,memory的訪問,數(shù)據(jù)的處理可以分解成上述6種類型的指令。由于底層的機器指令晦澀難懂,在存儲訪問和數(shù)據(jù)處理的時候,人們更傾向于用高級語言C來進行描述。C又是如何最終轉(zhuǎn)換成機器指令送給CPU的呢?這就要講到編譯的過程。
從C語言到機器語言總共要經(jīng)過3步,分別是編譯,匯編和鏈接。
C編譯成機器碼要通過預(yù)處理,編譯,匯編,鏈接四個步驟。這四個步驟由誰做的呢?答案是編譯器。
編譯器做的工作類似我們IC行業(yè)里面的綜合。在IC設(shè)計中,門級電路特別復(fù)雜,特別是當邏輯門數(shù)比較多時,通過直接設(shè)計邏輯電路變得非常困難。由此產(chǎn)生了verilog。我們通過Verilog描述電路的功能,然后通過DC進行綜合,讓我們很方便的進行大規(guī)模數(shù)字邏輯電路的設(shè)計。
在軟件層面,編譯器做得事情和綜合類似,編譯器的編譯的過程也分前端和后端。編譯器的前端主要完成分析階段讀取源程序,這其中包括詞法、語法和語法檢查,生成中間源代碼和符合表等。編譯器的后端,綜合階段通過中間源代碼表示和符號表生成目標程序。具體的編譯器各個階段做得事情,這里不做詳細介紹,感興趣的粉絲可以自己找資料學習。
C語言的編譯器有很多種,在我們芯片行業(yè),主要有GCC和LLVM。下面框圖簡單的描述了一個CPU編譯器組成。
我們都知道CPU的執(zhí)行效率和CPU的頻率及指令流水處理的效率有關(guān)系。很少人知道CPU的執(zhí)行效率還和編譯器有很大關(guān)系。編譯器對C代碼進行優(yōu)化可以大大的縮減代碼量,提高執(zhí)行效率。國內(nèi)有不少公司專門做這方面的研究。
上面我們講完編譯器的相關(guān)知識,在集成SOC環(huán)境的時候,我們需要集成工具鏈用于編譯C語言生成機器碼。
機器碼生成了,該怎么輸入給CPU使用呢?
介紹CPU boot的過程。對此我們先看下一個哈弗結(jié)構(gòu)的CPU的框架。
CPU通過指令總線從指令存儲器里面讀取指令進行操作,如果需要數(shù)據(jù)則從數(shù)據(jù)存儲器里面讀取數(shù)據(jù)處理。下面是一組真實的指令總線和數(shù)據(jù)總線。
[]
從上面的代碼中可以看到,指令總線和數(shù)據(jù)總線都有地址和數(shù)據(jù)信號以及一些握手信號。在CPU reset之后,CPU會主動通過指令總線去某個特定的位置讀取機器碼。下圖是CPU接口上一組輸入信號,boot_addr_i 就是指令CPU reset 之后從哪里開始讀代碼。
由此我們可以通過將編譯好的機器碼放在mem里面,然后設(shè)置boot_addr_i 指定到該mem的位置,實現(xiàn)一個最小的CPU boot系統(tǒng)。
實際芯片的模塊比這個最小系統(tǒng)復(fù)雜很多。存儲介質(zhì)上分為ROM,SRAM和Flash,一些大的芯片還有DDR等。
看到這些存儲模塊,有些人想了,是不是可以把機器碼放在里面?這就要講到boot的幾種模式。
第一種將代碼放在SRAM里面直接啟動。具體操作的手段是將CPU的boot_addr_i 指定到SRAM的位置,在仿真開始的時候?qū)ode load 進 SRAM memory里面即可實現(xiàn) 從SRAM里面boot。SRAM boot的一個問題是每次關(guān)電,SRAM都會被清除,無法保存code。
第二種是將代碼放在ROM里面,但是很不幸,ROM的空間非常小,如果將整段代碼放在ROM里面不太現(xiàn)實。所以很多人將ROM 用作存儲引導(dǎo)代碼,即bootrom code。然后由bootrom code 跳轉(zhuǎn)到SRAM或者flash執(zhí)行的位置。
第三種是將代碼放在Flash里面。通過bootrom code 從flash里面將代碼搬到SRAM里面執(zhí)行。另外一種方式是通過bootrom code 去配置flash 進入XIP狀態(tài),然后CPU直接從flash里面讀取指令進行執(zhí)行。通過這類方式boot的好處是掉電代碼沒有遺失,是真正產(chǎn)品應(yīng)用的方式。
上面是三種在我們SOC驗證中經(jīng)常用到的boot方式,真實芯片的boot比這個復(fù)雜得多。
以ARM為例,系統(tǒng)boot會被分成三個步驟。
第一級bootloader:引導(dǎo)加載程序,即bootrom code,會選擇哪種方式啟動系統(tǒng)(EMMC,UART,SPI…)。第一級bootloader執(zhí)行完之后會跳轉(zhuǎn)到第二級bootloader。
第二級bootloader:用于硬件的初始化,比如初始化時鐘,中斷,看門狗等,這段代碼放在SRAM中執(zhí)行。執(zhí)行完這個會跳到第三級bootloader。
第三級bootloader: 這個才是我們C代碼的入口,也就是我們寫的main函數(shù)在這里開始執(zhí)行。
bootrom是一門比較復(fù)雜的系統(tǒng)工程,在真正產(chǎn)品應(yīng)用中還需要考慮可靠性和安全性。但是對我們SOC驗證來說,在系統(tǒng)里面集成最基礎(chǔ)的三種boot方式即可滿足大部分驗證需求。
上期有朋友問我有沒有簡單的SOC驗證環(huán)境,答案是有,在公眾號后臺回復(fù)"SOC驗證"可獲得一個最小系統(tǒng)的SOC驗證環(huán)境。
https://github.com/openhwgroup/cv32e40p
上次說到CPU的boot,今天說說SOC環(huán)境的另外一種啟動方式。用C啟動SOC驗證環(huán)境有幾個問題。
一是CPU boot過程比較慢,每次仿真前都需要很長的一段初始化時間。
二是IP驗證環(huán)境的測試用例無法直接復(fù)用到SOC環(huán)境里面。
對于小型的芯片用C做仿真還可以,但是對于大型的SOC芯片,用C做仿真效率有點低。基于上面兩處不便,我們考慮能否用UVM直接接管CPU,然后通過SV/C直接下激勵。
上述方法是可行的,為了讓SOC環(huán)境跑的更快,用相應(yīng)的BUS的agent接管 CPU的總線,將CPU bypass過去,然后通過UVM的環(huán)境調(diào)用不同agent的driver,實現(xiàn)給不同模塊激勵。
如上圖所示,右邊是一個SOC,CPU通過總線訪問SPI,USB,PCIE,DDR,I2C等。在SOC驗證環(huán)境里面,通過usb_agt 接管去往USB的總線,用pcie_agt接管去往PCIE的總線。當然也可以用chip_agt 接管CPU出來的總線。總而言之做法就是通過UVM去接管系統(tǒng)的總線。
這樣我們可以bypass boot的過程,并且還可以實現(xiàn)IP的驗證環(huán)境在SOC驗證環(huán)境中復(fù)用。如果我們對C代碼進行一些封裝,還可以通過C訪問SV從而實現(xiàn)C test在這類環(huán)境的復(fù)用。
通過UVM接管CPU,bypass boot的過程,我們仿真的速度可以加快不少,但是SOC還是非常大,在編譯和仿真的時候,會消耗很多時間和內(nèi)存。為了加速,我們將不用的module用empty的module代替,只保留接口信息,模塊內(nèi)部不實現(xiàn),這樣可以大大減少SOC環(huán)境的邏輯單元數(shù)和信號的翻轉(zhuǎn)率,提升編譯和仿真速度。
上圖中,我們在測USB的時候會用到DDR,但是SPI,PCIE和I2C都不會用到,因此我們將這些模塊用空的module代替。采用這些手段,這個SOC的驗證環(huán)境就可以跑的比較快。
原文鏈接:https://blog.csdn.net/Michael177/article/details/125451339
相關(guān)推薦
- 2022-11-07 C語言字符串函數(shù)模擬實現(xiàn)流程介紹_C 語言
- 2023-03-23 python中decimal模塊的具體使用_python
- 2022-06-08 SpringCache通用緩存學習
- 2022-04-26 Android?Jetpack?Compose實現(xiàn)列表吸頂效果_Android
- 2022-08-16 一篇文章徹底搞懂Python切片操作_python
- 2022-02-27 Uncaught (in promise) Error: Redirected when going
- 2022-06-22 Python?Tkinter?GUI編程實現(xiàn)Frame切換_python
- 2022-05-29 C#中使用HttpPost調(diào)用WebService的方法_C#教程
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支