? ? ? ? 位流驗證,對于芯片研發是一個非常重要的測試手段,對于純軟件開發人員,最難理解的就是位流驗證。在FPGA芯片研發中,位流驗證是在做什么,在哪些階段需要做位流驗證,如何做?都是問題。
? ? ? ? 我們先整體的說一下:
? ? ? ? 首先:在硬件設計階段,位流驗證是設計驗證部的重要工作,它是為了驗證硬件設計的數字電路部分的合理性,對于FPGA芯片,主要就是對標準的架構組件進行驗證。如果相應的EDA軟件未成形之前,相應的位流需要通過手工單獨生成。
? ? ? ? 然后:在FPGA配套的EDA軟件開發階段,位流驗證也非常重要。因為EDA軟件的最大目標就是生成正確的位流,位流輸出是否符合預期,關系到軟件各個環節的正確性。所以,一般會將位流驗證做為重要的回歸測試手段,一方面,可以持續驗證最新輸出軟件的正確性,另外,如果芯片的底層架構發生變化,模型變更,仿真庫變更,也可以通過位流驗證,保證架構更改的正確性(架構主要是按照硬件設計對應的軟件模型,而硬件設計的這些模型,都會有對應的仿真庫和參考模型,用于驗證)。
? ? ? ? 最后:在生產測試階段,位流驗證同樣是非常好的測試手段,它可以測試位流寫入芯片后上板上芯片的效果,確認芯片實際的運行情況。在軟件中只是保證了邏輯上的正確,實際結合電氣特性和各種不同環境是否能正常可靠運行,可能通過位流加載后的效果進行驗證。加載到實際板上的效果,也可以通過驅動程序取出,與預期參老模型的結果做對比,驗證其準確性。
? ? ? ? 當然,位流驗證可能并不僅限于上面的三種情況(限于我了解的內容有限),但通過上面的描述,你可以發現,位流驗證本身是就是會跨多個部門的比較特殊的手段,在不同部門做驗證時,一定會存在配合,和一些有相似的工作。但是,因為各自的目的不同,發現錯誤后,定位和糾錯的方向也很不一樣。反以,反過來說,選擇的相應示例也會有些不同。
????????今天,我們只講在EDA軟件如何利用位流驗證,完成對EDA軟件的重要回歸測試。
? ? ? ? 大概的講法是:
? ? ? ? :我們會講解位流驗證依賴的框架UVM
? ? ? ? :會講一下UVM的實現平臺。
? ? ? ? :會講一下針對EDA軟件的驗證,會對哪些部分進行驗證,會使用什么樣的示例 。
? ? ? ? :發現問題后,會如何通過輸出去定位錯誤。
? ? ? ? :因為用于自動化回歸,也講一下相應的自動化平臺應該如何拱建。
? ? ? ? 首先,我們還是得再來理解一下位流驗證需要用到的UVM框架。(之前在單講測試時,也說過一次,但講得并不仔細)
一:UVM框架
1.1:理論
? ? ? ? Universal Verifacation Methodology:是一套基于SystemVerilog的標準驗證方法學。它提供了一套完整的框架,用于構建復雜的驗證環境,應用于芯片設計領域的功能驗證。旨在提高驗證的可重復性、可重用性和自動化程度。應該說,對于硬件設計的驗證,UVM是最基礎,最常用的平臺,離不開它。
2.1.1:DUT
? ? ? ? 待測設計——Design Under Test,就是你要驗證的設計單元。
????????如果你是要驗證/測試一顆 FPGA 芯片,DUT 一般會分為三種,一種是單Tile的設計,一種是多Tile的設計,還有就是整個芯片的設計。
? ? ? ? 注意這里我加了個bitstream,這并不是UVM必須的,加上bitstream是和我們今天要講的位流驗證扣題,也就是我們在驗證時,使用FPGA的位流文件,來形成DUT的功能。
? ? ? ? env:Testbenc Environment ,除了DUT,其它就是UVM的驗證環境了,它包含了一大堆東西,后面一個一個介紹。
- Sequencer:測試數據序列,因為測試時需要很多的輸入數據,我們按序列提供。
- Driver:如何數據輸入DUT的過程,可以理解為激勵的過程。
- Monitor:監控DUT的輸入/輸出信號
- Reference Model:參考模型,對應DUT的設計,提供相同行為的給果。
- 這里參考模型的運行,一般我們會使用仿真工具的內置實現來完成。
- Compare:比較DUT的輸出和參考模型的輸出,判斷是否匹配。
2.1.2:Sequencer
? ? ? ? Sitmulus:生成測試數據序列。我們需要基于測試的需求,產生數據,交給Driver來驅動到DUT。比如:你要測試DSP的乘法,那就是提供相應的輸入數值對。
class my_sequence extends uvm_sequence #(my_transaction);
? `uvm_object_utils(my_sequence)? task body();
? ? my_transaction tr;
? ? foreach (tr.data[i]) begin
? ? ? tr.data[i] = $urandom_range(0, 255); // 隨機生成 8 位數據
? ? ? start_item(tr); ? ? ? ? ? ? ? ? ? ? // 發送數據
? ? ? finish_item(tr);
? ? end
? endtask
endclass
2.1.3:Driver
? ? ? ? 接收Sequencer的測試數據并將其轉換為DUT的輸入信號。
? ? ? ? 這里可能需要模擬時序,比如:時鐘的同步,握手協議等。
class my_driver extends uvm_driver #(my_transaction);
? `uvm_component_utils(my_driver)? task run_phase(uvm_phase phase);
? ? forever begin
? ? ? seq_item_port.get_next_item(req); // 接收 sequencer 的數據
? ? ? @(posedge clk); ? ? ? ? ? ? ? ? ?// 時鐘同步
? ? ? dut_input = req.data; ? ? ? ? ? ?// 將數據驅動到 DUT
? ? ? seq_item_port.item_done();
? ? end
? endtask
endclass
2.1.4:Monitor
? ? ? ? 實時監控DUT的輸入和輸出信號,將監控到的數據送出到比較系統Compare,進行輸出分析。
class my_monitor extends uvm_monitor #(my_transaction);
? `uvm_component_utils(my_monitor)? task run_phase(uvm_phase phase);
? ? forever begin
? ? ? @(posedge clk);
? ? ? tr.data = dut_output; ? // 采集 DUT 的輸出數據
? ? ? analysis_port.write(tr); // 將數據發送給 Scoreboard
? ? end
? endtask
endclass
2.1.5:Reference Model
? ? ? ? 參考模型,用于生成和DUT相同邏輯功能的輸出(Golden Model)。
? ? ? ? 基于相同的輸入激勵信號,獲得理想的輸出。
function bit [7:0] ref_model(input bit [7:0] data);
? return data + 1; // 示例:參考模型輸出為輸入加 1
endfunction
2.1.6:Compare
? ? ? ? 這里的Compare,可能是簡單的比較結果的輸出,也可能是比較復雜的Scoreboard(一個記錄數據表)。根據比較結果,輸出不匹配的情況,并輸出報告。
class my_scoreboard extends uvm_scoreboard;
? `uvm_component_utils(my_scoreboard)? task run_phase(uvm_phase phase);
? ? my_transaction ref_tr, dut_tr;
? ? forever begin
? ? ? ref_tr = ref_fifo.get(); // 從參考模型接收預期數據
? ? ? dut_tr = dut_fifo.get(); // 從 DUT 獲取實際輸出
? ? ? if (ref_tr.data !== dut_tr.data)
? ? ? ? `uvm_error("Mismatch", $sformatf("Expected: %0h, Got: %0h", ref_tr.data, dut_tr.data));
? ? end
? endtask
endclass
2.1.7:示例
? ? ? ? 我們再來一個完整的示例,說明一下各部分做的事情。
? ? ? ? DUT設計—— 一個簡單的8位加法器。
DUT代碼:(對于位流驗證,輸入不是這個,后面會舉例說明)
module adder(
? ? input ?logic [7:0] a,
? ? input ?logic [7:0] b,
? ? output logic [7:0] sum
);
? ? assign sum = a + b;
endmodule
UVM環境:
? ? ? ? 這里需要定義一個Transaction,因為每次激勵的執行都是不同的事務,事務標明輸入和輸出。
? ? ? ? Transaction 定義:
class my_transaction extends uvm_sequence_item;
? ? rand bit [7:0] a, b; ? // 輸入信號
? ? bit [7:0] expected_sum; // 參考模型生成的期望輸出? ? `uvm_object_utils(my_transaction)
? ? // 構造函數
? ? function new(string name = "my_transaction");
? ? ? ? super.new(name);
? ? endfunction
endclass
? ? ? ? Sequencer:
class my_sequence extends uvm_sequence #(my_transaction);
? ? `uvm_object_utils(my_sequence)? ? task body();
? ? ? ? my_transaction tr;? ? ? ? repeat (10) begin
? ? ? ? ? ? tr = my_transaction::type_id::create("tr");
? ? ? ? ? ? tr.a = $urandom_range(0, 255); ?// 隨機生成輸入 a
? ? ? ? ? ? tr.b = $urandom_range(0, 255); ?// 隨機生成輸入 b
? ? ? ? ? ? start_item(tr); ? ? ? ? ? ? ? ? // 開始傳輸數據
? ? ? ? ? ? finish_item(tr); ? ? ? ? ? ? ? ?// 結束傳輸數據
? ? ? ? end
? ? endtask
endclass
? ? ? ? Driver:
class my_driver extends uvm_driver #(my_transaction);
? ? `uvm_component_utils(my_driver)? ? // DUT 的接口
? ? virtual adder_if dut_if;? ? // 構造函數
? ? function new(string name = "my_driver", uvm_component parent);
? ? ? ? super.new(name, parent);
? ? endfunction? ? // 運行階段
? ? task run_phase(uvm_phase phase);
? ? ? ? forever begin
? ? ? ? ? ? seq_item_port.get_next_item(req); // 從 Sequencer 獲取數據
? ? ? ? ? ? @(posedge dut_if.clk); ? ? ? ? ? // 等待時鐘上升沿
? ? ? ? ? ? dut_if.a = req.a; ? ? ? ? ? ? ? ?// 驅動 DUT 輸入 a
? ? ? ? ? ? dut_if.b = req.b; ? ? ? ? ? ? ? ?// 驅動 DUT 輸入 b
? ? ? ? ? ? seq_item_port.item_done(); ? ? ? // 標記數據已完成
? ? ? ? end
? ? endtask
endclass
?
? ? ? ? Monitor:
? ? ? ? 輸入監控
class input_monitor extends uvm_monitor;
? ? `uvm_component_utils(input_monitor)? ? // DUT 接口
? ? virtual adder_if dut_if;
? ? uvm_analysis_port #(my_transaction) analysis_port; // 分析端口? ? function new(string name = "input_monitor", uvm_component parent);
? ? ? ? super.new(name, parent);
? ? endfunction? ? // 運行階段
? ? task run_phase(uvm_phase phase);
? ? ? ? forever begin
? ? ? ? ? ? @(posedge dut_if.clk); // 等待時鐘上升沿
? ? ? ? ? ? my_transaction tr = my_transaction::type_id::create("tr");
? ? ? ? ? ? tr.a = dut_if.a; // 采集 DUT 輸入 a
? ? ? ? ? ? tr.b = dut_if.b; // 采集 DUT 輸入 b
? ? ? ? ? ? analysis_port.write(tr); // 將交易數據發送給分析端口
? ? ? ? end
? ? endtask
endclass
? ? ? ?輸出監控:
class output_monitor extends uvm_monitor;
? ? `uvm_component_utils(output_monitor)? ? // DUT 接口
? ? virtual adder_if dut_if;
? ? uvm_analysis_port #(my_transaction) analysis_port; // 分析端口? ? function new(string name = "output_monitor", uvm_component parent);
? ? ? ? super.new(name, parent);
? ? endfunction? ? // 運行階段
? ? task run_phase(uvm_phase phase);
? ? ? ? forever begin
? ? ? ? ? ? @(posedge dut_if.clk); // 等待時鐘上升沿
? ? ? ? ? ? my_transaction tr = my_transaction::type_id::create("tr");
? ? ? ? ? ? tr.expected_sum = dut_if.sum; // 獲取 DUT 輸出 sum
? ? ? ? ? ? analysis_port.write(tr); ? ? // 發送到分析端口
? ? ? ? end
? ? endtask
endclass
???????? Compare:
class my_scoreboard extends uvm_scoreboard;
? ? `uvm_component_utils(my_scoreboard)? ? uvm_analysis_imp #(my_transaction, my_scoreboard) input_analysis_imp;
? ? uvm_analysis_imp #(my_transaction, my_scoreboard) output_analysis_imp;? ? my_transaction expected_tr, actual_tr;
? ? function new(string name = "my_scoreboard", uvm_component parent);
? ? ? ? super.new(name, parent);
? ? ? ? input_analysis_imp = uvm_analysis_imp #(my_transaction, my_scoreboard)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ::type_id::create("input_analysis_imp", this);
? ? ? ? output_analysis_imp = uvm_analysis_imp #(my_transaction, my_scoreboard)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?::type_id::create("output_analysis_imp", this);
? ? endfunction? ? // 輸入數據分析
? ? function void write(input my_transaction tr);
? ? ? ? expected_tr = tr;
? ? ? ? expected_tr.expected_sum = expected_tr.a + expected_tr.b; // 參考模型
? ? endfunction? ? // 輸出數據分析
? ? function void write(output my_transaction tr);
? ? ? ? actual_tr = tr;? ? ? ? // 比較 DUT 輸出和參考模型的期望值
? ? ? ? if (actual_tr.expected_sum !== expected_tr.expected_sum) begin
? ? ? ? ? ? `uvm_error("Mismatch", $sformatf("Expected: %0d, Got: %0d",
? ? ? ? ? ? ? ? ? ? ? expected_tr.expected_sum, actual_tr.expected_sum));
? ? ? ? end
? ? endfunction
endclass
2.1.8:位流驗證
那對于位流驗證,UVM是如何使用的呢?
1:首先,必須準備好你的FPGA的EDA軟件(準備好運行時需要的 Flow 的tcl命令)。給出你的芯片仿真時需要的Primitve仿真庫。
2:針對你要測試的全芯片或者部分tile,選擇你要測試的設計用例(需要有一定的代表性噢,可以是N多,需要有一定覆蓋度),用 flow 生成仿真用的門級網表文件,并輸出用例的route結果,輸出最終的bitstream。
3:開始對要測試的用例,編寫參考模型(也是另外一種實現方案)。
4:編寫激勵(測試)程序,提供相應的激勵數據序列。
5:在TestBench上,針對 DUT 的 RefModel模型進行仿真,驗證兩者輸出是否一致,如果一致,說明位流測試正常。比較的方法,要看測試用例的功能。
6:如果測試不正常,可以利用中間輸出,日志輸出,波形輸出等信息進行定位,查看出錯原因。
好了,那UVM框架是如何實現的呢?有什么支撐平臺和工具嗎?
1.2:支撐
? ? ? ? 那UVM這種框架是如何通平臺來支撐它的呢?我們以Synopsys的VCS為例,來說明它是如何支持的(當然,也可以使用Mentor提供的QuestaSim)。
1.2.1:工具? ? ? ?
VCS(Verlog Compiler Simulator)是業界領先的仿真工具,原生支持UVM,它提供了一系列的工具和功能,全而覆蓋了UVM測試平臺中的各項工作。
UVM 組件 | VCS 支持工具/功能 |
---|---|
Sequence | SystemVerilog 編譯器直接支持 UVM sequence 的隨機生成和調試。 |
Driver | 通過 VCS 的時鐘精確仿真,支持 UVM driver 精確地驅動 DUT 信號。 |
Monitor | UVM 信號分析器,與 DVE 圖形工具集成,監控信號流。 |
Compare Scoreboard | 與覆蓋率分析工具集成,支持寄存器覆蓋率和功能覆蓋率的檢查。 |
Debug? | 提供圖形化的 UVM Phase 調試工具,支持動態調試和波形交互分析。 |
Verification?? ? | 集成 DVE 和 Verdi 工具,查看波形和調試測試平臺的運行時行為。 |
? ? ? ?
????????基于VCS的功能,要實現UVM平臺,還需要封裝一些標準的命令,達成常見的功能。
1.2.2:平臺
? ? ? ? 為了實現UVM的基礎功能,我們需要提供一些封裝功能,我們稱之為平臺。因為VCS并不是直接針對UVM的,所以,我們需要針對它做一些封裝,然后我們基于封裝來使用,這樣,看起來就更像是一個針對UVM實現的平臺了。
? ? ? ? 基本功能如下:(封裝方法可以使用Python或其它腳本語言來實現)
- 平臺初始化:
? ? ? ? ?確認 測試平臺的主目錄,測試工程目錄,測試用例目錄,工具目錄,輸出目錄……
- 設置重要參數:
? ? ? ? 測試的代碼列表庫
? ? ? ? 測試用例的分組
? ? ? ? 運行次數
? ? ? ? 是否調試模式:提供更多log輸出
? ? ? ? 提供隨機種子數:用于控制輸入參數的隨機種子,控制測試數據的生成。
? ? ? ? ……
- 編譯/構建:
? ? ? ?我們的testbench的代碼還是相對比較復雜的,另外,它也依賴于背后的仿真平臺提供的大量的庫文件,所以,我們一般需要對testbench的代碼進行構建,輸出各種我們需要的環境。
????????首先要對DUT代碼進行編譯,一般是SystemVerilog代碼。
? ? ? ? 一般會使用 Makefile,需要編寫相應的makefile,主要是需要將用到的UVM的動態庫和引用資源進行構建。VCS有一些針對UVM的支撐庫。
- ?仿真:
????????直接調用VCS的仿真,有低功耗的仿真模式可選
- 波形分析:
???????? 輸出波形,用于Verdi波形調試
- 代碼覆蓋率統計:
????????統計測試的代碼覆蓋率
????????……
1.2.3:運行
? ? ? ? 在運行期,為了保證示例可以并行執行,一般會使用HPC集群環境。我們可以使用LSF集群管理,通過 bsub 來將相應的任務,提交到HPC中運行。
比如:
‘一般會把任務分為多條,按順序將任務放入同一個隊列,保證先后次序
bsub -n 1 -M 20480 -q dv_test -Is "上面封裝的命令,完成編譯或仿真或波形分析的功能"
以上是運算支撐最基本的要求。詳細的實現,我們后面會展開給個實例來講。
二:位流驗證
? ? ? ? 對于位流驗證,我們今天要講的主要是 FPGA的EDA工具測試,在EDA工具的Flow已基本成形的情況下,就可以開始搭建位流驗證平臺了,用于回歸/驗證EDA工具的功能。
2.1:流程圖
我們先來解釋一下上面的典型流程:
- 測試用例RTL文件
????????使用FPGA的器件的用例。測試用例文件,一般是DeviceModel提供的一些適合于驗證功能的標準用例。作為待測用例。(這些用例,一般是由簡到繁)
- EDA Flow
????????FPGA的軟件工具的運行flow,在自動化運行時,一般是采用無界面的tcl命令來執行。
? ? ? ? 這里需要保留多個輸出:
? ? ? ? 綜合/映射后的網表:這是針對所有Primitve的電路實現,可以理解為羅列出,我們的設計最終實際用到了哪些邏輯的實例。就是可以看到設計最終使用的Instance,有明確的標識名稱。
? ? ? ? Route后輸出的路由文件:這個用來定位所有實例Instance在芯片中實際的物理位置。也就是Impl后,實際上物理芯片上使用的邏輯塊和相應的布線。結合上一步的輸出,可以明確查到實例具體的位置,以及走線的路徑。
? ? ? ? Bitstream 位流:這個是生成的bitstream,這個作為Dut的輸入,直接加載到測試平臺(如:VCS),加上提前準備好的芯片的原生的仿真庫,仿真平臺可以實際的模擬芯片的運行,并且得到相應的運行中結果和中間輸出。
- 用例的TestBench
? ? ? ?根據實際情況,生成的tb文件。包含激勵,定位,比較的邏輯。
? ? ? ?測試用例表:原始的測試用例
? ? ? ?Primitive行為模型:明確這個Primitive的行為是什么,在尋找參考模型時,需要找到對應的參考實現。
? ? ? ? 解析輸入/輸出管腳:找出輸入IO 和 輸出IO,這個可以在Route 中找到。
? ? ? ? 編寫用例參考模型:根據Primitive的行為和你的設計用例,寫等價的功能。注意,這里的等價模型,一般是仿真平臺直接執行出結果(并不是基于FPGA的邏輯電路來執行)。
? ? ? ? 設計輸入的激勵信號:設計測試的輸入數據和相應的序列。
? ? ? ? 編寫比較函數:看如何比較兩者的輸出。對于返回值 ,可以簡單比較輸出。對于時序,可能需要檢查波形,一般是選擇幾個關鍵的點,不可能全部檢查。
- 位流測試平臺
? ? ? ? 結合位流文件,仿真庫,testbech ,使用UVM平臺進行實際的運行。完成代碼的編譯,構建,仿真,結果比較的功能。
- 測試結果
? ? ? ? 實際比較結果,將結果輸出到指定位置,并形成報告。
? ? ? ? 對于失敗的報告,還可以通過查看其它輸出(日志,波形等),具體進行問題定位。
? ? ? ? 對于覆蓋度的統計,可以查看目前回歸用例的覆蓋度,進而逐漸提升。
2.2:驗證的問題
? ? ? ? 如果2.1驗證出問題,那可能有哪些問題呢?我們可以看看。
- 文件的問題
可能是測試用例的問題,route輸出的問題(net丟失之類),postmap輸出的問題…… - IOPackage的問題
可能是IO Pad的錯誤,這可能是IO Package的問題。可能是輸入Pad,也可能是輸出Pad不對。IO配置不對,配置信號不對,綁定約束的處理問題。 - 路由的問題
提供的switch box 的連接不對。 - 邏輯單元不對
模塊的配置有問題,配置問題導致功能出錯,模塊到Switch box的連線問題 - 其它
DeviceModel建模的問題,也有可能是Primitive實現的問題(硬件方面的)
? ? ? ? 具體的定位,可以通過源代碼,PostMap文件,route文件來查到具體的實例,然后在VCS的仿真器上,查看具體時點的輸出,這里可能是需要使用工具查看波形。
? ? ? ? route文件,postmap文件(這個一般是打平的flattern文件)的具體格式就不方便給出樣例了,這個每家FPGA的格式會有所不同。
三:FPGA芯片驗證方法
????????我們設計出來的FPGA芯片,是否能滿足預期。我們要保證我們提供給用戶的FPGA上每一個器件的功能是符合預期的,也就是單個tile的功能,以及Tile之間的連接,整體芯片的邏輯是完全正常的。
????????所以,我們需要針對單Tile,多Tile,fullchip做位流驗證。方法就是使用上面的位流驗證平臺。針對這三種方法,我們分別來說明,說明應該如何設計樣例 ,來達成相應的結果。
3.1:單Tile位流驗證
? ? ? ? 對于每一種Tile做單獨的測試(所有的Primitive),比如:CLB(LUT,CLA,DFF,SFTR……),CMT,IO,DSP,BRAM,EMRAM,FIFO,OBUF,IBUF,IOBUF,……
? ? ? ? 并且也包括Tile內部的連接信號路由的驗證。
????????我們以CLB為例:
????????對于CLB,里面主要涉及不同的LUT,DFF,CLA,SFTR,需要設計一系列的用例,去覆蓋相關的器件使用。
? ? ? ? 我們以最簡單的 Lut2為例,來看看如何構建測試用例,參考用例,激勵數據,結果比較。
3.1.1:CLB —— LUT2
? ? ? ? 首先,我們要了解Lut2的原理,它是由2輸入1輸出組成,可以完成 2個單bit輸入1個輸出的任何邏輯。比如:a & b,a | b , a xor b。
? ? ? ? 一般來說,廠商會提供 LUT2的Primitive IP,我們假如提供的IP就叫做? YY_LUT2。
? ? ? ? 那么,對于Dut,那就很簡單了。注意? a & b 的真值 表是? 1000b 也就是 h8
? ? ? ? Dut的設計代碼:
moudule And2(
? ? ? ? ? ? ? ? input a,
? ? ? ? ? ? ? ? input b,
? ? ? ? ? ? ? ? output result
);
? ? ? ? YY_LUT2 #(.INIT(4'h8)) lut2(.Io(a), .I1(b), .O(result));
end module
? ? ? ? 將該代碼使用 eda flow 執行,生成 bitstream。
? ? ? ? 我們來看一下參考用例的寫法:
module RefModel(input A,
? ? ? ? ?input B,
?????????output Y);
assign Y = A & B ; // 參考模型的布爾函數
endmodule
? ? ? ? 以上的代碼,仿真工具在運行時,會在每個仿真周期,根據輸入數據的變化來重新輸出結果。對應的邏輯表達式的運算是在仿真器中執行(實際上就是語法解析,然后交給CPU來執行了)。
? ? ? ? 當然,你的示例還可以是? A | B,A xor B,若干的樣例。
? ? ? ? 另外:
- INIT=0 IS_C_INVERTED = 0 IS_CLR_INVERTED=1? ? 可以驗證 DFFCE 的功能
- 1bit加,1bit 減 可以驗證CLA功能
- wclk極性不反轉? 驗證?SFTR32
- 將INIT、IC_C_INVERTED、IS_PRE(CLR/R/S/)_INVERTED的值進行隨機,inst約束到FFA0 驗證?LPQCE
3.1.2:DSP
????????我們再以DSP為例,選擇合適的用例(針對DSPX18 的 2個輸入乘法)
? ? ? ? 直接調用 YY_DSP48_CPLX18 ,具體就不寫了。
? ? ? ? 具體如何設置用例,需要根據DSP48_CPLX18的輸入參數來設置,盡量保證相關的參數可覆蓋。
3.2:多Tile位流驗證
????????需要驗證 Tile間路由的正確性,在多個tile分配資源,全局信號,時鐘可以正常共享,跨tile的優化結果符合預期。主要是對一組tile,某個功能區域進行驗證。驗證多個tile的功能及其之間的交互。可以用來驗證協同工作,比如:DSP 與 BRAM的協同工作情況,驗證范圍有限,無法覆蓋全芯片的全局資源,比如:時鐘網絡,全局布線等。
需要構造如下用例:
- 長路徑信號傳輸:
- Tile間級聯:多個tile之間的邏輯級聯(比如:多級加法器)
- Tile內外通信:在不同Tile實現的模塊之間進行通信(如:FIFO,AXI總線)
? ? ? ??
3.3:全芯片位流驗證
????????對于全局資源(如:時鐘,全局線)的使用進行驗證。關注邊界行為(I/O引腳,DDR,PCIe)。
????????需要構建的用例 :
- 設計一條覆蓋盡可能多Tile的信號路徑,從一個邊界Tile傳播到對角線另一側。
- 在設計中啟動全局時鐘。
- 包含外部接口(I/O,DDR,PCIe)在設計中。
? ? ? ? 選用的用例,一般會是一些經典的電路設計,比如:FPGA一般會和閃存配合使用,那我們就選用一些標閃的閃存器件來搭建用例(因為閃存用例是有公開的行為模型和仿真庫的)
? ? ? ? 因為是針對整個芯片的測試,所以,激勵數據,應該采用jtag方式輸入,涉及到PRAM的操作。相對比較復雜,這里不再展開細說。
3.4:代碼的測試覆蓋率
? ? ? ? 測試是否有效,主要看覆蓋率,所以,在仿真運行中輸出測試覆蓋率,是非常重要的指標。
覆蓋率報告通常包括以下信息:
-
總體覆蓋率:
-
顯示整個設計的總體覆蓋率(如行覆蓋率、分支覆蓋率等)。
-
-
模塊級覆蓋率:
-
顯示每個模塊的覆蓋率詳情。
-
-
代碼行覆蓋率:
-
顯示每一行代碼是否被執行。
-
-
分支覆蓋率:
-
顯示每個分支是否被覆蓋。
-
-
條件覆蓋率:
-
顯示每個布爾表達式的條件組合是否被覆蓋。
-
-
狀態機覆蓋率:
-
顯示狀態機的所有狀態和狀態轉換是否被覆蓋。
-
-
翻轉覆蓋率:
-
顯示信號是否發生了 0 到 1 或 1 到 0 的翻轉。
-
? ?代碼覆蓋度能夠查看測試的完整度。是非常重要的參考指標。
????????最后我們來看看,要搭建一個自動化的驗證平臺,需要做一些什么樣的工作:
????????這部分是一個封裝動作,和驗證本身的關系并不是很大,但如果對驗證的細節不清楚,也不能搭建一個好的,可擴展的平臺,因為平臺的功能也不是一成不變的,需要有一個演進的過程。如果有好的設計,自然最佳。
四:位流驗證的自動化平臺
4.1:平臺架構
????????這軟件EDA的位流驗證的架構。如果驗證是上板驗證(生產測試中心)。那位流的運行就不是在仿真環境,而是在板上的物理芯片運行,然后想辦法把物理芯片的運行結果,按時序取回,然后進行對比。
4.2:資源管理
? ? ? ? 需要管理的資源:
- 平臺的代碼
? ? ? ? ? ? ? ? 主要是流程控制的代碼,Python,Shell腳本,主要是存放到Git中,應該需要管理版本,
? ? ? ? 一般會是解釋性腳本語言,不會有編譯/構建的過程。
- 測試工程?
? ? ? ? 每一次回歸測試,我們定義為一個工程。而工程會描述所有運行的輸入,輸出。
? ? ? ? 工程的定義:針對某個芯片,某種驗證方式,某個器件的測試,我們認為是一個驗證工程。
? ? ? ? 待驗證芯片——芯片的系列(架構),具體輸出的芯片版本號(鎖定的版本)
? ? ? ? 待驗證的內容——?FullChip,或者 TILE_CLB_LUT2,或者 BRAM & DSP 的聯合工程。
? ? ? ? 對應的仿真庫——不同驗證點,需要提供不同的仿真庫,比如 fullchip和單tile需要的仿真庫是不同的。但相對固定,基本上是提前準備好的。但是如果芯片的架構發生變化,需要做相應的更換。也可以理解芯片系列的版本發生變化。
? ? ? ? 對應的待測式DUT——待測試的DUT的測試用例。
? ? ? ? DUT 對應的RefModel—— 對應的參考模型。
? ? ? ? 相關的配置信息——可能存在一些配置,可能待測內容不同,配置會有所不同。略
? ? ? ? 輸出目錄——包括位流輸出目錄(包括一些中間文件輸出),最終輸出目錄。
- DUT Testbench
? ? ? ? 每個待測工程,都需要有一個TestBench 代碼,TestBench 用來定義整個測試的過程。包括如何使用生成的位流進行仿真運行,如何調用RefModel(Golden case)獲得結果,兩者如何進行比較,如何輸出。
? ? ? ? 注意,不同測試工程,可能代碼會有所不同。
- 測試用例
? ? ? ? 測試用例是針對芯片待測單元的調用。可能需要覆蓋待測單元的大多數輸入組合。這些用例需要進行統一管理,在需要時,在測試工程中配置。
? ? ? ? 比如:針對 LUT1的測試用例 (只需要初始化一下真值表即可)
? ? ? ? ? ? ? ? ? ? ? ? YY_LUT1 # ( INIT (2'h3) inst_lut1()? ? ? ? ? ? ? ? // o = a?
- 參考模型代碼
? ? ? ? 針對測試用例,與之對應的另外一種實現(不依賴于FPGA),直接在VCS中運行。如果需要考慮時序,該模型代碼需要打拍。
? ? ? ? 比如:assign o = a? 就是針對上面的LUT1用例的Golden case。
- 其它配置
? ? ? ? 配置EDA工具的運行環境,這個是可以按需配置,因為對于EDA,研發每天都會有新的版本。
4.3:調度平臺
? ? ? ? 因為需要自動化,必須要有調度,這樣可以定時自動執行。
? ? ? ? 可以通過腳本控制執行的入口和過程,控制超時時間,控制運行的隊列(串行還是并行),可以將大任務發到計算集群。
? ? ? ? 調度很簡單,一般使用 Jekins的 Pipeline即可,Jekins支持Shell,可以進行任務的編排。
4.4:位流生成
? ? ? ? 位流生成,就是使用j最新EDA和相應的flow tcl ,用來生成位流。
? ? ? ? 位流生成需要注意幾個點:
? ? ? ? ? ? ? ? 可能會添加固定的物理約束,簡化輸出,明確實際的 IOPAD。
4.5:仿真運行
? ? ? ? 對于test bencch 運行,會有多個步驟。
- 激勵數據的處理? ? ? ??
? ? ? ? 這里要看一下,是否需要形成有針對性的激勵數據。可能和位置轉換有關(實際位置可以通過位流輸出的 instance和 route信息,獲取實際的位置信息)。
- test bench 代碼編譯? ? ? ?
? ? ? ? 針對 test bench代碼,建議采用makefile進行編譯/構建,這樣比較容易針對VCS進行動態鏈接和引用,也定義輸出的動作。
- test bech 仿真運行
? ? ? ? 使用仿真平臺,輸入激勵,進行仿真,輸出波形,輸出代碼覆蓋度。
? ? ? ? 對Golden Case 進行運行,輸入激勵,執行輸出。
? ? ? ? 兩者進行比較,在仿真log中輸出
4.6:結果輸出
???????收集結果,確認是否成功,輸出最終報告。
? ? ? ?可能還會輸出一些必要的數據,波形,代碼覆蓋度之類。
五:其它
5.1:硬件設計驗證
? ? ? ? 對于硬件部的位流驗證,實際上基本上是一致的。不同之處主要有:
? ? ? ? 1:在EDA的位流生成功能不成熟前,需要有其它方式生成位流。
? ? ? ? 2:硬件驗證不通過的情況,會關注硬件本身的設計,而不是位流的生成。關注點會有所不同。
5.2:生產測試中心位流驗證
? ? ? ? 對于生產測試中心,需要實際上板測試。所以。
? ? ? ? 1:位流需要download到實際芯片上運行,激勵需要實際輸入到芯片。
? ? ? ? 2:參考模型與軟件一樣,但注意,大多數時候要考慮時序,而不是簡單的組合邏輯。
? ? ? ? 3:對于實際芯片的運行輸入/輸出,一般需要做特殊處理,比如:設計專用電路,完成激勵輸入,設計驅動程序將輸出數據寫入本地磁盤,然后通過磁盤文件獲取結果,進行比較。
? ? ? ? 輸出的文件需要表達時序信息。
? ? ? ? 4:生產測試發現問題,關注的是硬件的可靠性。
????????大概就是這樣了,對于仿真的實際運行的細節和實際的硬件相關,有空再說。