UVM寄存器模型:reg adapter实现和集成
目錄
1. 概要
2.?reg/bus adapter的實現
3. reg/bus adapter的集成
?4.?bus2reg()和reg2bus() 是如何被調用?
4.1 bus2reg()在哪里調用?
4.2?reg2bus()在哪里調用?
4.3 小結
1. 概要
? ? ? ? UVM寄存器模型有內建的抽象的read()和write()等寄存器訪問命令,實際的寄存器訪問需要通過對用于寄存器訪問的總線接口進行驅動來完成。典型的總線接口有AMAB總線家族、I2C總線、SPI總線等都可以用作寄存器訪問的總線接口。
? ? ? ? 在UVM驗證平臺中,要完成寄存器訪問,需要進行寄存器模型的抽象的read/write訪問動作與具體種類總線的bus transaction之間的轉換,這就是adapter(between reg and bus)所要扮演的角色。adapter的實現,更具體一點說是reg2bus和bus2reg兩個任務的實現隨實際使用的總線協議不同而不同。UVM有一個專門的類uvm_reg_adapter用作reg/bus adapter實現模板,用戶實現的reg/bus adapter class必須繼承于uvm_reg_adapter。
2.?reg/bus adapter的實現
????????reg/bus adapter的實現包含以下兩個要點:
- uvm_reg_bus_op與總線transaction中各自的數據映射。
- 實現reg2bus()和bus2reg()兩個函數,這兩個函數即實現了兩種transaction的數據映射,函數名則表明了它們的轉換方向。這兩個函數原型是預定義的,驗證開發者必須去實現其具體處理。
????????reg2bus()和bus2reg()兩個函數是uvm_reg_adapter class中定義的純虛函數(pure virtual function) ,如下所示(uvm_reg_adapter.svh):
virtual class uvm_reg_adapter extends uvm_object; ... // Function: reg2bus//// Extensions of this class ~must~ implement this method to convert the specified// <uvm_reg_bus_op> to a corresponding <uvm_sequence_item> subtype that defines the bus// transaction.//// The method must allocate a new bus-specific <uvm_sequence_item>,// assign its members from// the corresponding members from the given generic ~rw~ bus operation, then// return it.pure virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);// Function: bus2reg//// Extensions of this class ~must~ implement this method to copy members// of the given bus-specific ~bus_item~ to corresponding members of the provided// ~bus_rw~ instance. Unlike <reg2bus>, the resulting transaction// is not allocated from scratch. This is to accommodate applications// where the bus response must be returned in the original request.pure virtual function void bus2reg(uvm_sequence_item bus_item,ref uvm_reg_bus_op rw); ...? ? ? ? 此外,如果總線支持byte訪問,可以使能supports_byte_enable;如果總線UVC要返回response數據,則應當使能provides_response。參考以下UVM代碼(uvm_reg_adapter.svh):
virtual class uvm_reg_adapter extends uvm_object;// Function: new//// Create a new instance of this type, giving it the optional ~name~.function new(string name="");super.new(name);endfunction// Variable: supports_byte_enable//// Set this bit in extensions of this class if the bus protocol supports// byte enables.bit supports_byte_enable;// Variable: provides_responses//// Set this bit in extensions of this class if the bus driver provides// separate response items.bit provides_responses; ...? ? ? ? 以下為一個基于APB總線的寄存器訪問接口的adapter類的實現例。
class apb_reg_adapter extends uvm_reg_adapter;`uvm_object_utils(apb_reg_adapter)function new(string name = "apb_reg_adapter");super.new(name);provides_responses = 1;endfunctionfunction uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);apb_transfer t = apb_transfer::type_id::create("t");t.trans_kind = (rw.kind == UVM_WRITE) ? WRITE : READ;t.addr = rw.addr;t.data = rw.data;t.idle_cycles = 1;return t;endfunctionfunction void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);apb_transfer t;if (!$cast(t, bus_item)) begin`uvm_fatal("CASTFAIL","Provided bus_item is not of the correct type")return;endrw.kind = (t.trans_kind == WRITE) ? UVM_WRITE : UVM_READ;rw.addr = t.addr;rw.data = t.data;rw.status = t.trans_status == OK ? UVM_IS_OK : UVM_NOT_OK;endfunction endclass????????其中,uvm_reg_bus_op為UVM預定義類,包含以下成員:
????????如以上例碼所示,一般來說,adapter的實現其實就是bus2reg和reg2bus兩個函數的實現而已。reg2bus()完成的橋接場景是,如果用戶在寄存器級別做了操作,那么寄存器級別操作的信息uvm_reg_bus_op會被記錄,同時調用uvm_reg_adapter::reg2bus()函數。在完成了將uvm_reg_bus_op的信息映射到bus_trans(即以上代碼例中的apb_transfer)之后,函數將bus_trans實例返回。而在返回bus_trans之后,該實例將通過bus_seqeuncer傳入到bus_driver。這里的transaction傳輸是后臺隱式調用的,不需要主動發起。
????????bus2reg()函數的功能與reg2bus()相反,完成了從bus_trans到uvm_reg_bus_op的內容映射。在完成映射之后,更新的uvm_reg_bus_op數據最終返回至寄存器操作場景層。
????????對于寄存器操作,無論讀操作還是寫操作,都需要經歷調用reg2bus(),繼而發起總線事務,而完成總線事務發回反饋之后,又需要調用bus2reg(),將總線的數據返回至寄存器操作層面。
3. reg/bus adapter的集成
?
?圖1 UVM寄存器環境系統模型(取自[2])
????????上圖為UVM寄存器環境系統模型示意圖,但是有一點容易被誤解的地方是,adapter其實是一個相對獨立的組件,regmodel和predictor分別通過不同的方式間接引用同一個adapter的對象,而不是像上圖一樣在regmodel和predictor中各有一個adapter。
? ? ? ? adapter通常是放在env中,然后predictor通過句柄的方式引用adapter的對象,regmodel則是通過map.set_sequencer()來建立與adapter對象的關聯,如下圖所示:
????????以下為env中集成寄存器模型的代碼示例:
class i2c_env extends uvm_env;// top configuration and virtual interfacei2c_config cfg;virtual i2c_if vif;... // top register model and related componentsral_block_i2c rgm;apb_reg_adapter adapter;uvm_reg_predictor #(apb_transfer) predictor;`uvm_component_utils(i2c_env)function new (string name = "i2c_env", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);...if(!uvm_config_db #(ral_block_i2c)::get(this, "", "rgm", rgm)) begin`uvm_info("build_phase", "Unable to get ral_block_i2c from uvm_config_db and create a RGM locally", UVM_LOW)rgm = ral_block_i2c::type_id::create("rgm", this);rgm.build();rgm.lock_model();end...adapter = apb_reg_adapter::type_id::create("adapter", this);predictor = uvm_reg_predictor#(apb_transfer)::type_id::create("predictor", this);endfunction: build_phasefunction void connect_phase(uvm_phase phase);super.connect_phase(phase);...// register model integrationrgm.default_map.set_sequencer(apb_mst.sequencer, adapter);apb_mst.monitor.item_collected_port.connect(predictor.bus_in);predictor.map = rgm.default_map;predictor.adapter = adapter;endfunction: connect_phaseendclass?4.?bus2reg()和reg2bus() 是如何被調用?
????????UVM初學者很容易感到困惑的一個地方是,UVM驗證平臺中很多函數只需要用戶實現它們,并不需要對其進行調用,那實現它們干嗎呢?原因是UVM已經偷偷地幫助你在需要的時候進行了調用,所以用戶只管實現不管調用。回調函數都是屬于這一類。
? ? ? ? 具體一點,bus2reg()和reg2bus()的調用是如何發生的呢?
????????如前所述,一旦發生了寄存器訪問操作,reg2bus()會被隱式地調用用以將抽象的寄存器操作(read(), write(),etc)轉換為bus transaction,然后該bus transaction將由對應的sequencer轉發給bus driver,最后由bus driver生成接口波形驅動到DUT接口上去,這一切都因為以下這條語句建立的關聯為基礎,UVM自動地在后臺為你把所有其它的事情都干了。
rgm.default_map.set_sequencer(apb_mst.sequencer, adapter);
? ? ? ? 同樣,發生寄存器訪問操作時,bus monitor會將總線上觀測到的信號變化采樣并打包成bus transaction傳給predictor,然后preditor會調用adapter::bus2reg()將bus transaction再變回寄存器模型的抽象操作。為什么要這么做呢?這是因為predictor需要根據總線上監測到的信號變化狀況來預測接下來DUT中的真實的寄存器值(actual value)將會發生什么變化,并將這個變化反饋給寄存器模型,寄存器模型則據此更新mirror value,使得mirror value保持與actual value同步。關于UVM寄存器模型的mirror value、actual value與desired value三者之間關系、區別以及同步等也是比較把初學者搞昏頭的,需要另文專門解釋。
4.1 bus2reg() 在哪里被調用?
????????查閱UVM庫的源代碼可以找到bus2reg在以下三個地方被調用(不知道還有沒有其它地方?待進一步確認):
????????bus2reg() called in uvm_reg_map:????????
task uvm_reg_map::do_bus_write (uvm_reg_item rw,uvm_sequencer_base sequencer,uvm_reg_adapter adapter);...if (adapter.provides_responses) beginuvm_sequence_item bus_rsp;uvm_access_e op;// TODO: need to test for right trans type, if not put back in qrw.parent.get_base_response(bus_rsp);adapter.bus2reg(bus_rsp,rw_access);endelse beginadapter.bus2reg(bus_req,rw_access);end...task uvm_reg_map::do_bus_read (uvm_reg_item rw,uvm_sequencer_base sequencer,uvm_reg_adapter adapter);...if (adapter.provides_responses) beginuvm_sequence_item bus_rsp;uvm_access_e op;// TODO: need to test for right trans type, if not put back in qrw.parent.get_base_response(bus_rsp);adapter.bus2reg(bus_rsp,rw_access);endelse beginadapter.bus2reg(bus_req,rw_access);end...????????bus2reg() called in predictor:
class uvm_reg_predictor #(type BUSTYPE=int) extends uvm_component;`uvm_component_param_utils(uvm_reg_predictor#(BUSTYPE))...// Variable: adapter//// The adapter used to convey the parameters of a bus operation in // terms of a canonical <uvm_reg_bus_op> datum.// The <uvm_reg_adapter> must be configured before the run phase.//uvm_reg_adapter adapter;...// Function- write//// not a user-level method. Do not call directly. See documentation// for the ~bus_in~ member.//virtual function void write(BUSTYPE tr);uvm_reg rg;uvm_reg_bus_op rw;if (adapter == null)`uvm_fatal("REG/WRITE/NULL","write: adapter handle is null") // In case they forget to set byte_enrw.byte_en = -1;adapter.bus2reg(tr,rw);rg = map.get_reg_by_offset(rw.addr, (rw.kind == UVM_READ));...? ? ? ? uvm_reg_predictor(UVM寄存器環境中的preditor為該class的直接實例)中有一個adapter類型的句柄(該句柄將在env中指向真正的adapter對象),而adapter.bus2reg()就在uvm_reg_predictor::write()中被調用。而如以上函數說明所示,uvm_reg_predictor::write()本身不是一個user-level方法,不能直接調用。這也印證了以上bus2reg()不需要用戶顯式調用的描述(甚至predictor中連調用bus2reg()的函數都不需要用戶直接調用。。。再往前會追溯到哪兒去呢?這里就暫時放一下,有空時再回頭來徹底刨根究底地追追看)
4.2?reg2bus()在哪里調用?
????????查閱UVM庫的源代碼可以找到reg2bus在以下地方被調用(不知道還有沒有其它地方?待進一步確認):
? ? ? ? reg2bus() called in uvm_reg_map:????????
task uvm_reg_map::do_bus_write (uvm_reg_item rw,uvm_sequencer_base sequencer,uvm_reg_adapter adapter);...// perform accessesforeach(accesses[i]) begin uvm_reg_bus_op rw_access=accesses[i]; uvm_sequence_item bus_req;adapter.m_set_item(rw);bus_req = adapter.reg2bus(rw_access);adapter.m_set_item(null);......task uvm_reg_map::do_bus_read (uvm_reg_item rw,uvm_sequencer_base sequencer,uvm_reg_adapter adapter);...// perform accessesforeach(accesses[i]) begin uvm_reg_bus_op rw_access=accesses[i]; uvm_sequence_item bus_req;uvm_reg_data_logic_t data; int unsigned curr_byte_; curr_byte_=rw_access.data;rw_access.data='0;adapter.m_set_item(rw);bus_req = adapter.reg2bus(rw_access);......4.3 小結
? ? ? ? 總之,如上所述,UVM在后臺偷偷地把很多的事情干了。
????????一方面,這也正是UVM的便捷和強大之處,所有這些UVM在后臺偷偷地干了的事情其實都是標準化的操作處理,不需要開發者再一一顯式地去處理,避免了無謂的重新發明輪子,使得驗證開發者可以更加聚焦于高級事務。?
????????另一方面,這會使得初學者很不習慣,畢竟習慣了“所見即所得”,沒有看到的東西心里沒底啊,誰知道到底有沒有被執行啊。從心里沒底到慢慢成竹在胸泰然自若,這是成長的必經之路。
?主要參考文獻:
【1】路科驗證2022春季V2X課件
【2】UVM Register Environment (chipverify.com)
總結
以上是生活随笔為你收集整理的UVM寄存器模型:reg adapter实现和集成的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为教父任正非的别样视野(转)
- 下一篇: maxmemory-policy