說明
驗證需要包含對寄存器和存儲器的驗證,寄存器用來描述晶片配置資訊和狀态資訊
自己實作
可通過啟動讀寫寄存器的sequence來完成
sequence産生的寄存器事務傳遞給driver,driver來寫入寄存器的值或者讀取寄存器的值,monitor再從接口上擷取資訊,判斷是哪個寄存器和它的值,這是一種簡單的檢測寄存器的方法,但是在其他元件中難以啟動或者檢視某些寄存器的值,在某種情況下 scoreboard想檢視寄存器中某個的狀态,則不知道什麼時候去觸發這個,隻能通過事務狀态來啟動sequence 驅動到driver,然後用monitor擷取,這種做法相當繁瑣。

寄存器模組化RAL
RAL提供了一套資料結構,對寄存器進行模組化,執行個體化後作為元件的一部分。scoreboard就可以通過寄存器模型來通路DUT中的寄存器。使用RAL提供的API來通路,write寫, read讀。這個過程是寄存器模型自己完成的。
寄存器模型想要通路DUT中的寄存器還需要一個事務轉換器adapter,因為寄存器模型産生的事務類型可能與sequencer能接收的類型不一緻。轉換器需要自己完成。RAL模型産生的事務借助agent來通路DUT中寄存器/存儲器,這種為frontdoor模式,第二種是RAL通過DUT的設計層次路徑直接通路DUT中的寄存器,為backdoor模式。
工作模式
frontdoor
當在scoreboard或其他元件中調用api的時候,register_model.reg_name.read(…)或者register_model.reg_name.write(…)的時候,寄存器會根據寄存器名稱産生uvm_reg_item的事務對象,産生的名字會根據寄存器名稱reg_name自動生成,接着将對象類型轉換為uvm_reg_bus_op類型對象,并将該對象傳入轉換器中,然後轉換為sequencer可以接收的事務類型(使用者自定義類型),sequencer将資料發給driver,進而操作DUT,操作的結果會在寄存器模型中展現,如讀出的值會傳回給寄存器模型,這裡的整個過程由寄存器模型實作,需要消耗仿真時間。
backdoor
通過寄存器的層次結構直接引用DUT中的寄存器,将傳回值返給寄存器模型,backdoor模式不需要消耗仿真時間
register model在env中進行例化,其他元件使用句柄引用
寄存器模型
寄存器模型的構成圖如下:
轉換器
轉換器繼承UVM的基類uvm_reg_adapter。
轉換器類需要重載兩個函數
1、reg2bus 由寄存器模型的事務轉換成自己定義類型的事務,轉換為自動發給sequencer,
2、bus2reg 将自定義事務對象轉換為寄存器模型類型的事務,發給寄存器模型,
這兩個函數UVM平台自動調用,
register model 和adapter以及 sequencer的連結
借住寄存器模型中的map來實作,其map中有一個adpter句柄和一個sequencer句柄,将adpater對象指派給該句柄即可。
在測試平台中加入寄存器模型
為DUT建立寄存器模型,包含每一個寄存器
比如DUT有兩個寄存器和一個memary,如下圖所示
封裝reg類
//為每個寄存器進行模組化型
class config_reg_c externs uvm_reg
rand uvm_reg_filed f1 //建立第一個域
rand uvm_reg_filed f2
rand uvm_reg_filed f3
rand uvm_reg_filed f4
virtual function void bulid();//bulid方法,非phase
//執行個體化
f1 = uvm_reg_field::type_id::create(“f1”);
f2 = uvm_reg_field::type_id::create(“f2”);
f3 = uvm_reg_field::type_id::create(“f3”);
f4 = uvm_reg_field::type_id::create(“f4”);
//調用域的config,
//配置域的一些屬性
f1.configure(this,1,0,”RW”,0,’h0,1,1,1);//第一個參數是哪個寄存器,第二個是該域有幾位,
//第三個該field最低位在寄存器中位置,第四個參
//數表示域通路類型,第五個複位後的預設值,第
//六個表示是否可以被複位,第七個表示該域是否
//可以随機化,最後一個該field是否可以單獨操作
`uvm_object_utils(config_reg_c),
function new(string name = “config_reg_c”)
//第二個參數是寄存器總位寬,第三個是是否支援覆寫率統計,
super.new(name,8,UVM_NO_COVERAGE);
endfunction
endclass
其中存儲器需要從uvm_mem擴充
已上就完成寄存器模組化的工作。
封裝寄存器模型類
class reg_model_c extends uvm_reg_blocks;
rand config_reg_c config_reg;
rand mode_reg_c model_reg;
data_mem_c data_mem;
virtual function void bulid();//bulid方法,非phase
//執行個體化
config_reg = config_reg_c::type_id::create(“config_reg”,get_full_name());
config_reg. configure(this,null ,” config_reg”); //第三個參數是指定該寄存器
//在HDL路徑, 這個參數路徑
//用于backdoor的通路,
config_reg.build();
//其他寄存器用同樣方法建立
//建立map,第一個參數為名字,第二個為基位址,第三個系統總線位寬,
//機關為位元組,第四個為大小端
default_map = create_map(“default_map”,0,1,UVM_LITTLE_ENDIAN);
//添加寄存器,第一個參數為添加的reg名,第二個為reg偏移位址,
//用基位址和偏移位址結合表示實際位址,
default_map.add_reg(“config_reg”,‘h001c,”RW”);
`uvm_object_utils(reg_model_c),
function new(string name = “reg_model_c”)
super.new(name,UVM_NO_COVERAGE),第二個參數是是否支援覆寫率統計,
endfunction
end class
建立為實作前門操作的轉換器
從uvm_reg_adapter擴充,然後重載兩個函數
在env中執行個體化寄存器模型和轉換器
在env中執行個體化,建立,調用config_reg.bulid()函數就是在執行reg類中的bulid方法。
調用lock函數則鎖定,不可再編輯reg model ,調用reset函數完成初始化
在connect_phase中,調用map函數進行連接配接,最後調用reg_model.default_map.set_auto_predict(1).開啟預測功能,
最後在env中,将轉換器、sequencer、與寄存器的map建立關聯。在需要進行寄存器讀寫的地方進行API通路,比如在scoreboard調用寄存器模型,則在env中還需要将寄存器模型指派給scoreboard中例化的寄存器模型句柄。
寄存器模型的基本資料結構
寄存器模型API
read/write 方法 均支援前門後門通路,
使用前門通路的時候,read/write會産生事務,通過轉換器送到sequencer再送到driver,最終到達DUT,通路DUT内部寄存器值之後,将傳回來的結果通過predict自動更改期望值和鏡像值,最終使得期望值和鏡像值,與DUT内部的寄存器值保持一緻。
後門操作的時候,直接通過層次路徑,讀取寫入DUT内部的值,然後直接修改期望值和鏡像值,
peek/poke
peek幾乎相當于read的後門操作,poke幾乎相當于write的後門模式,
peek/poke不模拟寄存器的行為而是直接進行操作,
randomize : 随機化後會指派給期望值
update: 将期望值寫入DUT内部寄存器當中,然後比較期望值和鏡像值是否相同,不同則更新鏡像值。
mirror,:從DUT中讀出,寫入期望值和鏡像值。