<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      向UVM-TLM通信發(fā)起決戰(zhàn)

      前言

      開(kāi)頭想先說(shuō)點(diǎn)體會(huì),最早學(xué)習(xí)uvm時(shí),TLM通信這一章,自己最開(kāi)始并沒(méi)有很重視。到了親自搭驗(yàn)證環(huán)境時(shí)才發(fā)現(xiàn)TLM至關(guān)重要,沒(méi)有TLM,產(chǎn)生的事務(wù)無(wú)法在各個(gè)驗(yàn)證組件之間流通。這就好比人空有一副骨架,但沒(méi)有血液在流通。不掌握TLM機(jī)制,會(huì)導(dǎo)致很多代碼看不明白。

      個(gè)人總結(jié)的TLM的難點(diǎn)如下:

      • 端口類(lèi)非常的多,且大量用到參數(shù)化的類(lèi)這種寫(xiě)法
      • 組件之間的連接該用那個(gè)端口類(lèi)比較模糊,沒(méi)有一個(gè)清晰的架構(gòu)圖。

      基于上述自己的短板,所以有了這篇文章,希望能對(duì)這部分有個(gè)全面的梳理和了解。

      梳理的結(jié)果有三部分:

      1. 理論概念部分:port,export,imp的關(guān)系
      2. 淺析源代碼部分:TLM端口類(lèi)的類(lèi)庫(kù)地圖,并根據(jù)源代碼淺析他們之間的繼承關(guān)系
      3. 實(shí)戰(zhàn)部分:uvm驗(yàn)證環(huán)境端口連接關(guān)系圖,這對(duì)于實(shí)際搭建uvm驗(yàn)證環(huán)境端口類(lèi)的選取非常有用

      一、理論概念部分

      1.1 uvm1.2中,TLM1.0和TLM2.0的關(guān)系?

      去看uvm_pkg.sv中的內(nèi)容,會(huì)發(fā)現(xiàn)里面同時(shí)包括了tlm1和tlm2

      去看tlm1和tlm2中的內(nèi)容,發(fā)現(xiàn)tlm2并不是對(duì)tlm1中的類(lèi)進(jìn)行了完善和優(yōu)化,tlm1中出現(xiàn)的類(lèi),在tlm2中沒(méi)有再出現(xiàn),tlm2中定義了tlm1中完全沒(méi)有的全新的類(lèi)。所以tlm2.0是完全的新的東西。

      而對(duì)于uvm的初級(jí)使用,基本上只會(huì)涉及到tlm1.0的內(nèi)容。tlm2.0是更高階的玩法。因此本篇只解析TLM1.0,僅TLM1.0就夠我喝一壺的了。

      接口與方法差異:

      • TLM 1.0 定義了諸如 put()get()peek() 等基礎(chǔ)的傳輸方法,組件之間的通信基于這些簡(jiǎn)單的方法實(shí)現(xiàn)。例如,一個(gè)發(fā)起方組件調(diào)用 put() 方法將事務(wù)發(fā)送給目標(biāo)方組件。
      • TLM 2.0 引入了新的接口和方法,其通信機(jī)制更為復(fù)雜和精確。它有 nb_transport_fw()nb_transport_bw() 等方法,用于支持雙向通信和精確的時(shí)序建模。這些新的接口和方法與 TLM 1.0 的接口在功能和使用方式上有很大不同,不能直接相互調(diào)用。

      時(shí)序建模方式差異:

      • TLM 1.0 對(duì)時(shí)序的支持非常有限,通常不考慮事務(wù)傳輸?shù)木_時(shí)間,主要關(guān)注功能驗(yàn)證。
      • TLM 2.0 強(qiáng)調(diào)精確的時(shí)序建模,通過(guò)時(shí)間注解來(lái)描述事務(wù)的傳輸時(shí)間和延遲。這種差異使得 TLM 1.0 組件和 TLM 2.0 組件在處理時(shí)序時(shí)難以直接協(xié)同工作。

      1.2 TLM1端口類(lèi)型及端口方法

      首先,端口是不能單獨(dú)存在的,它必須是被例化在某個(gè)component中。端口就相當(dāng)于是component的門(mén),而門(mén)不能是孤立的單獨(dú)存在。 要想使用TLM機(jī)制,就必須要在對(duì)應(yīng)的組件中創(chuàng)建相應(yīng)的端口,TLM的功能是通過(guò)端口來(lái)實(shí)現(xiàn)的。

      component就像房子,而端口就是房子的門(mén)和窗戶。如果沒(méi)有端口,component之間就是孤立的

      在TLM機(jī)制中,擁有port類(lèi)型端口的組件是發(fā)起操作的主動(dòng)方(master),而擁有imp類(lèi)型端口的組件是被動(dòng)方(slave)

      端口類(lèi)型分為

      • port,export,imp
      • analysis_port,analysis_export,analysis_imp

      總體分為兩大類(lèi),帶analysis的和不帶analysis的。

      • 兩類(lèi)端口之間不互通。不能混用,即非analysis端口之間可以互相連接,analysis端口之間可以互相連接。但是非analysis端口和analysis端口之間不能互相連接

      • 不帶analysis的端口,只能單個(gè)點(diǎn)對(duì)點(diǎn)連接。優(yōu)先級(jí)port>export>imp。連接方式有:

        port.connect(port)port.connect(export)port.connect(imp)  export.connect(export)export.connect(imp) 
        
      • 帶有analysis類(lèi)型的端口表示可以一對(duì)多連接。其他情況與非analysis端口保持一致


      端口阻塞方法(阻塞當(dāng)前進(jìn)程):

      put(input T t)
      發(fā)起端把數(shù)據(jù)包發(fā)送給目標(biāo)端。數(shù)據(jù)流向?yàn)榘l(fā)起段到目標(biāo)端
      task類(lèi)型,阻塞當(dāng)前進(jìn)程,直到trans發(fā)送成功
      get(output T t)
      發(fā)起段向目標(biāo)端索要數(shù)據(jù)包。數(shù)據(jù)流向?yàn)槟繕?biāo)端到發(fā)起端
      task類(lèi)型,阻塞當(dāng)前進(jìn)程,直到trans獲取成功
      peek(output T t)

      和get方法一樣,區(qū)別是peek是獲取數(shù)據(jù)包的復(fù)制包

      task類(lèi)型,阻塞當(dāng)前進(jìn)程,直到trans獲取成功

      端口非阻塞方法(不阻塞當(dāng)前進(jìn)程):

      try_put(input T t)

      嘗試發(fā)送trans,執(zhí)行成功返回1,失敗返回0

      function類(lèi)型,不會(huì)阻塞當(dāng)前進(jìn)程,傳輸可能成功也可能失敗

      can_put()

      檢查接收端是否準(zhǔn)備好了接收事務(wù),執(zhí)行成功返回1,失敗返回0

      function類(lèi)型,不會(huì)阻塞當(dāng)前進(jìn)程

      try_get(output T t)嘗試獲取trans,function類(lèi)型,其他同上
      can_get()檢查對(duì)方是否能夠返回事務(wù),function類(lèi)型
      try_peek(output T t)function類(lèi)型,其他同上
      can_peek()function類(lèi)型,其他同上
      write()為analysis類(lèi)型端口獨(dú)有且僅有的方法,非阻塞 TODO

      幾點(diǎn)結(jié)論:

      • port,export,imp體現(xiàn)的是控制流而非數(shù)據(jù)流。地位優(yōu)先級(jí)port>export>imp。put操作中,數(shù)據(jù)從port流向imp,get操作中,數(shù)據(jù)從imp流向port,這類(lèi)似于master發(fā)起的寫(xiě)和讀。操作都是由地位更高的master來(lái)發(fā)起的。analysis類(lèi)型的同理。
      • 在兩個(gè)端口的連接過(guò)程中,只有高優(yōu)先級(jí)的才能調(diào)用connect函數(shù),而相對(duì)低優(yōu)先級(jí)的只能作為connect函數(shù)的參數(shù)。不能倒反天罡。
      • connect函數(shù)調(diào)用要有始有終。開(kāi)始一定是port發(fā)起,結(jié)束一定是imp端口。如果port和imp直接連接,那么總共調(diào)用一次connect函數(shù)port.connect(imp)。如果中間有export。這條連接線的結(jié)尾一定不能是export,export還需要連到最終的imp上。port.connect(export),export.connect(imp)。

      1.3 TLM原理

      以put方法為例,TLM傳輸可以分為幾個(gè)步驟:

      • 在connect phase中通過(guò)connect函數(shù)將端口連接
      • 主控方的端口發(fā)起操作,調(diào)用put任務(wù)
      • 在port端口的put任務(wù)中,調(diào)用了與其連接的export端口的put任務(wù)
      • 在export端口的put任務(wù)中,調(diào)用了與其連接的imp端口的put任務(wù)
      • 在imp端口的put任務(wù)中,調(diào)用了imp所在的component的put任務(wù)

      上述的原理是基于概念圖的抽象解釋,于是引發(fā)了如下疑問(wèn):

      1. 這些方法在原型類(lèi)中都是空的,最終的實(shí)現(xiàn)都是在imp所在的component即slaveB中完成的。那么slaveB中的put()任務(wù)究竟該怎么寫(xiě)?
      2. 源頭的port端口調(diào)用put任務(wù)后,是如何引發(fā)后續(xù)端口的put任務(wù)的?

      其實(shí)在port端口的put任務(wù)中,調(diào)用了與之相連的export的put任務(wù)。而在export的put任務(wù)中,又調(diào)用了與之相連的imp端口的put任務(wù)。imp的put任務(wù)中又調(diào)用了imp所在的component的put任務(wù)。

      而port端口的put任務(wù)中,之所以能調(diào)用export的put任務(wù)。根本前提是通過(guò)connect函數(shù)將port和export連接成功之后,port端口類(lèi)中拿到了指向export端口的句柄。其他同理。這部分的具體實(shí)現(xiàn)將在下文中源代碼解析部分詳細(xì)闡述。


      到此為止,通過(guò)一些抽象的圖初步理解了TLM通信的基本原理。但是如果真正去看一個(gè)uvm驗(yàn)證環(huán)境,會(huì)發(fā)現(xiàn)還是看不懂,會(huì)看到各種奇奇怪怪的類(lèi)出現(xiàn)。只根據(jù)幾個(gè)概念圖去了解原理,而不去看真正的代碼實(shí)現(xiàn),根本不能叫做理解TLM機(jī)制!!!

      uvm中,基于上面提到的各種端口類(lèi)型都提供了一系列的類(lèi)。實(shí)際驗(yàn)證環(huán)境中,各種端口類(lèi)都是基于uvm提供的這些類(lèi)來(lái)例化的。

      因此,必須從源頭出發(fā),全面透徹的梳理TLM1中的類(lèi),清楚有哪些類(lèi),這些類(lèi)可以分為幾部分?這些類(lèi)之間的繼承關(guān)系是什么?在實(shí)際搭建環(huán)境時(shí),該選取什么樣的類(lèi)?


      二、走到代碼中去

      2.1 TLM1中用到的class全覽

      tlm1中用到的所有類(lèi)都集中在了這些文件中了,從上往下看可以分為四個(gè)部分

      2.2 TLM1中的端口類(lèi)

      uvm_tlm_if_base#(T1,T2)  ★★★

      這個(gè)類(lèi)是tlm1中所有端口類(lèi)的基類(lèi)。注意,該類(lèi)是最基礎(chǔ)的基類(lèi),它沒(méi)有從任何類(lèi)擴(kuò)展而來(lái),注意端口類(lèi)并不是從uvm_object或者uvm_component擴(kuò)展而來(lái)的

      這個(gè)類(lèi)的主要作用是將端口的最基礎(chǔ)的方法做了封裝。該類(lèi)中包含的方法有:

      put(),get(),peek(),try_put(),can_put(),try_get(),can_get(),try_peek(),can_peek(), transport(),nb_transport(),write()

      uvm_tlm_if_base是一個(gè)virtual class。不能被實(shí)例化,只是做了一些定義,其內(nèi)部的虛方法也只是聲明了名字,方法內(nèi)部只有一句uvm_report_error。

      這意味著從uvm_tlm_if_base擴(kuò)展而來(lái)的子類(lèi),如果要調(diào)用這些方法,必須對(duì)這些虛方法進(jìn)行重寫(xiě)。否則將會(huì)報(bào)錯(cuò)


      uvm_sqr_if_base#(T1,T2)  ★★★

      uvm_sqr_if_base也是一個(gè)基類(lèi),它不從任何類(lèi)擴(kuò)展而來(lái),和uvm_tlm_if_base的地位是一樣的。而且這個(gè)類(lèi)是專門(mén)用于sequence,sequencer,driver之間的通信的。 該類(lèi)的作用也是封裝了一些方法:

      get_next_item(),try_next_item(),item_done(),wait_for_sequences(), has_do_available(), get(),peek(),put(),put_response(),disable_auto_item_recording(),is_auto_item_recording_enabled()

      同樣,這些方法必須在子類(lèi)中被重寫(xiě),否則將會(huì)引發(fā)uvm_report_error


      uvm_port_component_base

      這個(gè)類(lèi)繼承自u(píng)vm_component,是個(gè)抽象類(lèi),內(nèi)部定義了一些純虛方法:

      get_connected_to(),get_provided_to(),is_port(),is_export(),is_imp

      這個(gè)類(lèi)是干什么用的?


      uvm_port_component#(PORT)

      繼承自u(píng)vm_port_component_base,所以也是一個(gè)uvm_component類(lèi)。會(huì)傳入一個(gè)PORT參數(shù),在類(lèi)內(nèi)部,PORT類(lèi)會(huì)聲明一個(gè)句柄m_port,uvm_port_component類(lèi)在實(shí)例化時(shí)會(huì)傳入一個(gè)PORT類(lèi)的句柄port。 最終m_port指向的是傳入的port。

      這個(gè)類(lèi)中所有的function和task都是圍繞m_port展開(kāi)的。

      這里的函數(shù)調(diào)用很有意思,這里定義的函數(shù)是is_port,是對(duì)父類(lèi)uvm_port_component_base類(lèi)中純虛方法is_port的重寫(xiě)。函數(shù)內(nèi)部調(diào)用的是m_port.is_port()。這里比較奇怪,如果PORT默認(rèn)是uvm_object類(lèi)型的話,是沒(méi)有is_port()這個(gè)函數(shù)的。所以參數(shù)化的類(lèi),傳入的參數(shù),是根據(jù)實(shí)際傳入的類(lèi)型來(lái)看的

      父類(lèi)中如果有純虛方法(pure virtual function),子類(lèi)在繼承時(shí),必須對(duì)純虛方法進(jìn)行實(shí)現(xiàn)


      uvm_port_base#(IF) ★★★★★

      uvm_port_base是整個(gè)TLM1中所有類(lèi)的核心。這個(gè)類(lèi)極其極其重要,后面會(huì)發(fā)現(xiàn)所有的port,export,imp的端口類(lèi)都是從此類(lèi)擴(kuò)展而來(lái)。

      uvm_port_base#(IF)類(lèi)的聲明很有意思,給該類(lèi)傳入一個(gè)參數(shù)IF,該參數(shù)作為uvm_port_base的父類(lèi)。及uvm_port_base具有了IF類(lèi)的全部特性。

      uvm_port_base在實(shí)際使用時(shí),傳入的IF參數(shù)要么是uvm_tlm_if_base#(T,T),要么是uvm_seqr_if_base(T,T)。T為該端口實(shí)際要處理的transaction事務(wù)類(lèi)

      在該類(lèi)中,還有一個(gè)寫(xiě)的巧妙的地方。在uvm_port_base類(lèi)內(nèi)部,typedef這個(gè)類(lèi)為this_type,并將this_type作為uvm_port_component的PORT參數(shù)傳入。 聲明了一個(gè)uvm_port_component的句柄,m_comp

      在該類(lèi)中,定義了非常多的方法。列舉一部分:

      is_port(),is_export(),is_imp(),connect()

      connect函數(shù)是整個(gè)的核心。port和export,port和imp,export和export,export和imp之間的連接都是通過(guò)connect函數(shù)實(shí)現(xiàn)的。整個(gè)的實(shí)現(xiàn)方法是非常復(fù)雜的,這里不深入研究。


      uvm_*_port#(T)

      在實(shí)際使用時(shí),傳入的參數(shù)類(lèi)T為該端口要處理的transaction事務(wù)類(lèi)

      port類(lèi)型的端口類(lèi)非常多,統(tǒng)計(jì)共有23個(gè),看著眼花繚亂,其實(shí)有規(guī)律可循,可以分成如下幾個(gè)部分。

      圖片來(lái)自于博客:UVM Tutorial for Candy Lovers – 20. TLM 1 – ClueLogic

      什么情況下該用什么樣的port類(lèi)?

      上面的圖把繼承關(guān)系描述的非常清楚,最右側(cè)是擴(kuò)展而來(lái)的23個(gè)子類(lèi),這些子類(lèi)之間的本質(zhì)區(qū)別在于內(nèi)部封裝的方法不同。

      這里以put_port為例,看上面的類(lèi)圖,從名字上會(huì)發(fā)現(xiàn)有如下規(guī)律:

      uvm_blocking_put_port#(T),uvm_nonblocking_put_port#(T),uvm_put_port#(T),這三個(gè)都含有put,從源代碼可以看出,它們是封裝了*put方法相關(guān)的類(lèi)

      這三個(gè)類(lèi)之間的區(qū)別在于,封裝的方法類(lèi)型不一樣。上面講到了put()任務(wù)為阻塞類(lèi)型,而try_put()方法和can_put()方法為非阻塞類(lèi)型。

      • 從名字可以看出,uvm_blocking_put_port#(T)為阻塞類(lèi),所以其只能包含阻塞方法put()。
      • uvm_nonblocking_put_port#(T)為非阻塞類(lèi),所以其只能包含非阻塞方法,try_put(),can_put()
      • uvm_put_port#(T)既可以阻塞,也可以非阻塞,所以三種都包括

      因此,一個(gè)component使用什么樣的端口,取決于主控方想要發(fā)起的操作是什么。如果masterA的端口想要執(zhí)行put()任務(wù),那么只能使用uvm_blocking_put_port#(T)和uvm_put_port#(T)這兩類(lèi)端口。如果masterA的端口想要執(zhí)行try_put()或者can_put(),那么只能使用uvm_nonblocking_put_port#(T)的端口類(lèi)。

      在文件中看其他的類(lèi),和上面所說(shuō)的邏輯是完全一樣的,這里不再贅述,通過(guò)一張圖來(lái)進(jìn)行整理

      uvm_*_export(T)

      在實(shí)際使用時(shí),傳入的參數(shù)T為該端口要處理的transaction事務(wù)類(lèi)

      export類(lèi)型的端口類(lèi)從uvm_port_base繼承而來(lái),也有23個(gè)子類(lèi),可以發(fā)現(xiàn)它們和port類(lèi)型的端口一一對(duì)應(yīng)。

      數(shù)量一一對(duì)應(yīng)是必須的,必須保證使用的端口類(lèi)的前綴完全一致。因?yàn)樵谑褂胏onnect函數(shù)連接時(shí),會(huì)先檢查連接的端口類(lèi)型的前綴是否一致。否則會(huì)報(bào)錯(cuò)

      如uvm_nonblocking_get_port#(T)的前綴是uvm_nonblocking_get_。它只能和uvm_nonblocking_get_export#(T)或者uvm_nonblocking_get_imp#(T)相連

      uvm_*_imp(T,IMP)

      注意,imp類(lèi)型的端口類(lèi)傳入的參數(shù)有兩個(gè),T是該端口要處理的transaction事務(wù)類(lèi),IMP是該imp端口所在的component類(lèi)

      imp類(lèi)型的端口類(lèi)從uvm_port_base繼承而來(lái),也有23個(gè)子類(lèi),和上述兩類(lèi)端口一一對(duì)應(yīng)。

      不同端口類(lèi)型的連接規(guī)則

      port可以向port連接,可以向export發(fā)起連接,可以向imp發(fā)起連接

      export可以向export發(fā)起連接,可以向imp發(fā)起連接

      imp不能向任何端口發(fā)起連接

      層級(jí)的要求是個(gè)問(wèn)題,需要探討


      2.3 TLM1中的FIFO類(lèi)

      注意FIFO類(lèi)和端口類(lèi)是完全不同的,F(xiàn)IFO類(lèi)屬于組件,是component。而端口類(lèi)必須是在component類(lèi)中例化的。

      重視FIFO類(lèi)在使用中的重要性

      在實(shí)際驗(yàn)證環(huán)境中會(huì)遇到需要將進(jìn)程1中的componentA連接到進(jìn)程2中的componentB的情況,因?yàn)門(mén)LM組件需要在自己的進(jìn)程中工作(解耦合)

      之前的端口直連的過(guò)程是,只存在一個(gè)進(jìn)程,port端口調(diào)用方法,會(huì)引發(fā)一系列的方法調(diào)用。

      有些情況下,兩個(gè)平級(jí)的組件的run_phase是并行執(zhí)行的。它們?cè)诟髯缘木€程中調(diào)用自己的方法。這時(shí)就需要有一個(gè)緩沖區(qū)。即componentA發(fā)出的事務(wù)先放在一個(gè)FIFO里存起來(lái),componentB在執(zhí)行到自己的線程時(shí),再?gòu)腇IFO里去取。


      uvm_tlm_fifo_base#(T)

      uvm_tlm_fifo_base#(T)繼承于uvm_component,是一個(gè)virtual class,只能被繼承,不能被實(shí)例化。fifo類(lèi)可以看做是驗(yàn)證環(huán)境中的一個(gè)組件。在fifo類(lèi)中定義了非常多的端口和方法。

      包含的端口

      在uvm_tlm_fifo_base#(T)中,只定義了三種類(lèi)型的端口

      • uvm_put_imp#(T,IMP)
      • uvm_get_peek_imp#(T,IMP)
      • uvm_analysis_port#(T)

      注意,在uvm_tlm_fifo_base#(T)中沒(méi)有export類(lèi)型端口。

      雖然圖上標(biāo)注的都是export端口名,但是從源代碼看出,這些都是imp類(lèi)的句柄名。雖然起名叫export,但實(shí)際是imp類(lèi)型。為什么要這樣有意而為呢?

      答案:

      雖然有這么多的句柄,但是在new函數(shù)中,只實(shí)例化了一個(gè)put_export,一個(gè)get_peek_export,一個(gè)put_ap,一個(gè)get_ap。 其余的句柄并沒(méi)有單獨(dú)實(shí)例化,而是指向了這四個(gè)實(shí)例。所以在圖上,沒(méi)有被實(shí)例化的句柄,用淺顏色標(biāo)注。

      聲明的方法

      build_phase(),flush(),size(),put(),get(),peek(),try_put(),try_get(),try_peek(),can_put(),can_get(),can_peek(),ok_to_put(),ok_to_get(),ok_to_peek(),is_empty(),is_full(),is_used()

      這些方法都是空的,需要在子類(lèi)中被重寫(xiě),否則會(huì)報(bào)錯(cuò)。


      uvm_tlm_fifo#(T)和uvm_tlm_analysis_fifo#(T)

      由于uvm_tlm_fifo_base#(T)是fifo類(lèi)的基類(lèi),并且是virtual class。所以只定義了一些基礎(chǔ)的公共變量和方法。不能直接拿來(lái)使用。

      我們?cè)趯?shí)際搭建驗(yàn)證環(huán)境時(shí),用到的fifo類(lèi)都從該基類(lèi)擴(kuò)展而來(lái)。有兩種,分別是uvm_tlm_fifo#(T)以及uvm_tlm_analysis_fifo#(T)。

      圖片來(lái)自于博客:UVM Tutorial for Candy Lovers – 20. TLM 1 – ClueLogic

      • uvm_tlm_fifo#(T)繼承了uvm_tlm_fifo_base#(T),并沒(méi)有再額外聲明端口,只是重寫(xiě)了uvm_tlm_fifo_base中的方法
      • uvm_tlm_analysis_fifo#(T)繼承自u(píng)vm_tlm_fifo,多了一個(gè)uvm_analysis_imp類(lèi)型的端口,analysis_export


      一個(gè)關(guān)鍵問(wèn)題:uvm_tlm_fifo是如何實(shí)現(xiàn)fifo的特性的

      uvm_tlm_fifo是一個(gè)類(lèi),其具有fifo先入先出特性的核心是內(nèi)部例化了一個(gè)mailbox類(lèi)。mailbox本身就具有fifo的性質(zhì)。

      mailbox機(jī)制可以參考:


      使用uvm_tlm_fifo的工作原理

      • connect:componentA.port.connect(uvm_tlm_fifo.put_export),componentB.connect(uvm_tlm_fifo.get_export)
      • 在componentA的run_phase中,調(diào)用componentA.put(),從而調(diào)用uvm_tlm_fifo.put_export.put(),進(jìn)而調(diào)用uvm_tlm_fifo.put()。此時(shí)會(huì)把trans放入uvm_tlm_fifo的mailbox中
      • 在componentB的run_phase中,調(diào)用componentB.get(),從而調(diào)用uvm_tlm_fifo.get_export.get(),進(jìn)而調(diào)用uvm_tlm_fifo.get()。此時(shí)trans會(huì)從mailbox中出來(lái)。

      所以最終put()和get()方法的實(shí)現(xiàn)都是在imp所在的component類(lèi)中實(shí)現(xiàn)的。uvm_tlm_fifo#(T)中的這些方法繼承于uvm_tlm_fifo_base,并對(duì)這些方法進(jìn)行了重寫(xiě)。

      這些方法都是對(duì)mailbox的操作,以及調(diào)用put_ap和get_ap的write()函數(shù)

      這里put_ap和get_ap也沒(méi)有和別的口連接,調(diào)用它們的write有什么用? 調(diào)用write函數(shù),則put_ap和get_ap必須有所連接,否則應(yīng)該會(huì)報(bào)錯(cuò)吧。但是什么時(shí)候會(huì)把put_ap和get_ap連接呢?和誰(shuí)連接呢?必須要進(jìn)行連接嗎?


      analysis_port和analysis_fifo的區(qū)別和聯(lián)系

      剛開(kāi)始寫(xiě)代碼時(shí),會(huì)經(jīng)常混淆analysis_port和analysis_fifo。如果把前面的梳理清楚,這里我們自然就清楚兩者有著本質(zhì)的區(qū)別。

      注意analysis port和analysis fifo有著本質(zhì)的不同,前者是端口類(lèi),而后者是FIFO類(lèi),F(xiàn)IFO可以認(rèn)為是一個(gè)組件component,在FIFO中,例化了非常多的imp端口以及若干的analysis port端口


      2.4 TLM1中的Channel類(lèi)

      暫未使用過(guò),之后遇到再補(bǔ)充。


      2.5 sequence機(jī)制中用到的端口類(lèi)

      sequence機(jī)制是事務(wù)產(chǎn)生和發(fā)送的核心機(jī)制。涉及到sequencer和driver之間的事務(wù)傳輸。用到的端口類(lèi)也比較特殊。只有一種前綴對(duì)應(yīng)的port,export,imp端口。這里把上述類(lèi)庫(kù)地圖的最后一部分單獨(dú)截圖出來(lái)。

      這三種seq_port類(lèi)是

      • uvm_seq_item_pull_port#(REQ,RSP)
      • uvm_seq_item_pull_export#(REQ,RSP)
      • uvm_seq_item_pull_imp#(REQ,RSP,IMP)

      它們也是繼承自u(píng)vm_port_base#(IF),但是和其他端口類(lèi)的區(qū)別是,繼承的uvm_port_base#(IF)的IF參數(shù)是uvm_sqr_if_base#(REQ,RSP)。而不是uvm_tlm_if_base#(T,T)。兩者的區(qū)別在2.2節(jié)中已經(jīng)描述。

      這三類(lèi)端口的典型使用場(chǎng)景就是在sequence機(jī)制中。在uvm_driver中例化了uvm_seq_item_pull_port#(REQ,RSP),在uvm_sequencer中例化了uvm_seq_item_pull_imp#(REQ,RSP,IMP)。

      sequence機(jī)制中的TLM傳輸
      1. connect:在agent中,連接driver和sequencer。my_drv.seq_item_port.connect(my_seqr.seq_item_export)
      2. 在my_drv的run_phase中,調(diào)用seq_item_port.get_next_item(),進(jìn)而調(diào)用了my_seqr.seq_item_export.get_next_item(),進(jìn)而調(diào)用了my_seqr.get_next_item(),此時(shí)my_seqr收到my_drv的數(shù)據(jù)請(qǐng)求。會(huì)檢查是否有sequence發(fā)送到my_seqr,如果沒(méi)有則處于等待狀態(tài)。
      3. seq調(diào)用seq.start(my_seqr),將產(chǎn)生的事務(wù)發(fā)送給my_seqr。此時(shí)事務(wù)通過(guò)my_seqr傳遞給my_drv。
      4. my_drv處理完事務(wù)之后,調(diào)用seq_item_port.item_done(),表示結(jié)束,最終調(diào)用的是my_seqr.item_done()

      2.6 TLM機(jī)制的源代碼解析:

      在上面的傳輸過(guò)程中,多次描述到這樣一個(gè)過(guò)程:

      當(dāng)調(diào)用port.put()方法時(shí),會(huì)引發(fā)調(diào)用與之相連的imp.put()方法,進(jìn)而會(huì)調(diào)用imp所在的component類(lèi)的put()方法。

      那么由此引發(fā)兩個(gè)疑問(wèn):

      1. port.put()是如何引發(fā)后續(xù)方法的調(diào)用的?
      2. 最終的put()方法是在imp所在的component類(lèi)中實(shí)現(xiàn)的,具體要寫(xiě)成什么,才算實(shí)現(xiàn)了put()?

      在"tlm1/uvm_ports.svh"文件中定義了各種各樣的port類(lèi),定義寫(xiě)法都是一樣的,這里找一個(gè)拆開(kāi)解析

      首先,uvm_blocking_put_port#(T)繼承自u(píng)vm_port_base#(IF),這里傳入的IF參數(shù)是uvm_tlm_if_base#(T,T)類(lèi)。所以u(píng)vm_blocking_put_port繼承自u(píng)vm_port_base進(jìn)而繼承自u(píng)vm_tlm_if_base。 uvm_blocking_put_port傳入的參數(shù)T,最終會(huì)傳入到uvm_tlm_if_base中的參數(shù)(T,T)。 這里的參數(shù)T一般來(lái)說(shuō)是流經(jīng)端口的事務(wù)類(lèi)。是uvm_sequence_item的子類(lèi)。

      在uvm_blocking_put_port中重寫(xiě)了uvm_tlm_if_base中的put任務(wù),在put任務(wù)中調(diào)用了this.m_if.put()。this.m_if是從uvm_port_base中繼承的,m_if是uvm_port_base類(lèi)的一個(gè)句柄。

      這里的this.m_if指向的是與uvm_blocking_put_port相連的uvm_blocking_put_imp的實(shí)例。

      這里有了一個(gè)關(guān)鍵性疑問(wèn),在put_port中的m_if,是在什么時(shí)候指向的put_imp實(shí)例?

      很自然的會(huì)想到connect函數(shù),因?yàn)橹挥姓{(diào)用port.connect(imp)才建立兩個(gè)端口之間的聯(lián)系。

      走進(jìn)connec()函數(shù)

      代碼太長(zhǎng),這里就不貼了,總結(jié)connect函數(shù)主要干的事情。

      connect()函數(shù)傳入的參數(shù)為一個(gè)uvm_port_base類(lèi)型的句柄,provider

      1. 檢查provider是否為空,是否是自己本身,檢查provider的m_if_mask和自己的m_if_mask關(guān)系
      2. 檢查端口連接關(guān)系,不能是export連port,自己本身不能是imp等等
      3. 檢查relationship,更復(fù)雜的層級(jí)關(guān)系要滿足
      4. 以上都滿足之后,說(shuō)明端口連接是合法的,就把provider放入當(dāng)前port端口類(lèi)中的關(guān)聯(lián)數(shù)組m_provided_by中。同時(shí)provider也把當(dāng)前port類(lèi)放入自己的關(guān)聯(lián)數(shù)組m_provided_to中

      會(huì)發(fā)現(xiàn),connect()函數(shù)并沒(méi)有對(duì)m_if的任何操作。

      我想說(shuō)的是接下來(lái)這部分,將是我看uvm以來(lái)最沖擊我的一段代碼。這段比較細(xì)節(jié),即使不清楚也無(wú)所謂。

      uvm_port_base中,唯一出現(xiàn)m_if賦值的地方是:

      尋找set_if(()被何時(shí)被調(diào)用

      在uvm_port_phase中的resolve_bindings()函數(shù)中的最后一行,調(diào)用了set_if()函數(shù)。

      resolve_bindings()函數(shù)做的事情是:

      如果當(dāng)前端口不是imp端口,那么會(huì)遍歷m_provided_by這個(gè)關(guān)聯(lián)數(shù)組,這個(gè)關(guān)聯(lián)數(shù)組中是上述connect函數(shù)執(zhí)行之后,存放的與當(dāng)前port相連的端口。先調(diào)用了連接端口的resolve_bindings。 然后調(diào)用了m_add_list。  將m_provided_by中的值放到m_imp_list關(guān)聯(lián)數(shù)組中。

      最終調(diào)用了set_if()。在set_if中調(diào)用了get_if。最終m_if指向的是m_imp_list關(guān)聯(lián)數(shù)組中的第一個(gè)imp實(shí)例。

      那么resolve_bindings()是何時(shí)被調(diào)用的呢?

      不起眼的m_comp是關(guān)鍵。在uvm_port_base中,例化了一個(gè)uvm_component類(lèi)型的類(lèi)。

      m_comp的作用一個(gè)是繼承了來(lái)自u(píng)vm_component的一些report方法,便于打印一些信息。另外是m_comp在實(shí)例化之后,會(huì)根據(jù)phase機(jī)制,自動(dòng)執(zhí)行一些函數(shù)。

      在m_comp中,有一個(gè)resolve_bindings函數(shù),會(huì)調(diào)用m_port.resolve_bindings()函數(shù)。

      而m_comp中的resolve_bindings函數(shù)是重寫(xiě)的uvm_component的resolve_bindings()函數(shù)。

      而uvm_component的resolve_bindings()函數(shù)是在end_of_elaboration phase開(kāi)始之前自動(dòng)執(zhí)行的。

      至此,整個(gè)的順序就已經(jīng)清晰了。


      回到最開(kāi)始uvm_blocking_put_port#(T)中put()任務(wù)的描述:

      在put(T t)中,調(diào)用了this.m_if.put(t)。注意此時(shí)port端口處理的事務(wù)t,通過(guò)task的參數(shù)傳遞到了this.m_if.put(t)中。

      再進(jìn)到uvm_blocking_put_imp#(T)中,看其內(nèi)部定義的put任務(wù)

      可以注意到imp類(lèi)型的類(lèi),其參數(shù)多了一個(gè)IMP,這個(gè)IMP是端口所屬的component類(lèi)本身。一般在component中例化該imp端口時(shí),會(huì)傳入this。

      在imp類(lèi)中,聲明IMP的一個(gè)句柄m_imp,imp類(lèi)的put(T t)任務(wù)中,調(diào)用m_imp的put(t)任務(wù)。最終masterA中的trans,被slaveB拿到。

      put()任務(wù)的參數(shù)t,在調(diào)用過(guò)程中傳遞,是整個(gè)TLM通信中事務(wù)傳輸?shù)淖罱K實(shí)現(xiàn)。對(duì)于get()任務(wù),參數(shù)的傳遞方向改為output,與put()方向相反。

      2.7 使用宏 `uvm_*_imp_decl

      注意,該宏只針對(duì)imp類(lèi)的端口

      該宏出現(xiàn)解決的問(wèn)題基于如下場(chǎng)景

      不同于之前的一對(duì)一連接,現(xiàn)在有componentA和componentC都要和componentB連接。將會(huì)面例如下問(wèn)題:

      當(dāng)按照常規(guī)方法,做如下連接時(shí),compA.portA.put(t)最終會(huì)調(diào)用compB.put(t),而compC.portC.put(t)最終也會(huì)調(diào)用compB.put(t)。如果A和C同時(shí)向B發(fā)起傳輸,將會(huì)同時(shí)調(diào)用put,并且無(wú)法解決各自的需求。這顯然是不合理的。

      class componentA extends from uvm_component;     uvm_put_port#(A_trans)   portA;     // ……     task run_phase(uvm_phase phase);         portA.put(A_trans);        endtask endclass  class componentC extends from uvm_component;     uvm_put_port#(C_trans)   portC;     // ……     task run_phase(uvm_phase phase);         portC.put(C_trans);        endtask endclass   class componentB extends from uvm_component;     uvm_put_imp#(A_trans,this)   impAB;    uvm_put_imp#(C_trans,this)   impCB;         task put();         // ……      //這里將會(huì)引發(fā)矛盾和沖突    endtask endclass    class test_env extends from uvm_env;     componentA  compA;     componentB  compB;     componentC  compC;          function void connect_phase(uvm_phase phase);         compA.portA.connect(compB.impAB);         compC.portC.connect(compB.impCB);    endfunction endclass
      

      自然而然的會(huì)想到,在componentB中定義兩個(gè)put方法,put_A()和put_C()方法。

      • 當(dāng)發(fā)起compA.portA.put()時(shí),最終調(diào)用compB.put_A()方法
      • 當(dāng)發(fā)起compC.portC.put()時(shí),最終調(diào)用comB.put_C()方法

      以此來(lái)實(shí)現(xiàn)兩路傳輸?shù)莫?dú)立性。但是依靠原有的框架,使用原有的類(lèi),是無(wú)法實(shí)現(xiàn)的。因?yàn)樵械膇mp類(lèi)中,方法是固定寫(xiě)死的,不會(huì)有我們?nèi)藶槎x添加的put_A()和put_C()。

      我們可以做的是自定義新的impAB類(lèi)和impCB類(lèi),重新定義imp中的put()方法

      • 在impAB類(lèi)中調(diào)用put()方法時(shí),調(diào)用的是compB.put_A()方法
      • 在impCB類(lèi)中調(diào)用put()方法時(shí),調(diào)用的是compB.put_B()方法

      而這所有的區(qū)別,僅在于后綴的不同。uvm中提供了宏幫我們來(lái)完成這個(gè)過(guò)程。


      `uvm_*_imp_decl宏共有23種,這個(gè)宏展開(kāi)后其實(shí)就是對(duì)比常規(guī)的23種imp類(lèi)的重新定義。

      uvm_blocking_put_imp_decl(SFX)

      uvm_nonblocking_put_imp_decl(SFX)

      uvm_put_imp_decl(SFX)

      uvm_blocking_get_imp_decl

      uvm_nonblocking_get_imp_decl(SFX)

      uvm_get_imp_decl(SFX)

      ……

      以u(píng)vm_blocking_put_imp_decl(SFX)為例,展開(kāi)解析:

      這個(gè)宏是帶參數(shù)的宏,這個(gè)參數(shù)就是人為定義的后綴。使用該宏時(shí),就會(huì)產(chǎn)生一個(gè)新class的聲明。如`uvm_blocking_put_imp(_A)等價(jià)于聲明了一個(gè)class,類(lèi)名為 uvm_blocking_put_imp_A。

      在類(lèi)內(nèi)部,又調(diào)用了兩個(gè)宏,展開(kāi)來(lái)看:

      第一個(gè)宏就是在常規(guī)的imp類(lèi)中用到的宏,聲明了new函數(shù),以及指定了type_name。沒(méi)有什么特別之處。

      第二個(gè)宏,和常規(guī)imp類(lèi)中的宏不同,這里重新定義了put()任務(wù)中的內(nèi)容:

      至此,使用這個(gè)宏之后的代碼如下:

      `uvm_put_imp_decl(_A) `uvm_put_imp_decl(_C)// 兩個(gè)宏的使用一定要在class之外,因?yàn)楹瓯旧泶淼木褪莄lass的聲明。  class componentA extends from uvm_component;     uvm_put_port#(A_trans)   portA;     // ……     task run_phase(uvm_phase phase);         portA.put(A_trans);        endtask endclass  class componentC extends from uvm_component;     uvm_put_port#(C_trans)   portC;     // ……     task run_phase(uvm_phase phase);         portC.put(C_trans);        endtask endclass   class componentB extends from uvm_component;     uvm_put_imp_A#(A_trans,this)   impAB;          //使用新定義的imp類(lèi)    uvm_put_imp_C#(C_trans,this)   impCB;          //使用新定義的imp類(lèi)         task put_A();   // task名字必須和后綴保持一致        // ……         endtask       task put_B();   // task名字必須和后綴保持一致        // ……         endtask   endclass    class test_env extends from uvm_env;     componentA  compA;     componentB  compB;     componentC  compC;          function void connect_phase(uvm_phase phase);         compA.portA.connect(compB.impAB);         compC.portC.connect(compB.impCB);    endfunction endclass
      

      至此,上述情景的傳輸過(guò)程如下:

      注意:在新定義的imp類(lèi)中,put任務(wù)是不帶后綴的,依舊是叫put()。這里的名字必須和port中的保持一致。區(qū)別是調(diào)用的不再是componentB中的put(),而是componentB中的put_*()


      三、實(shí)戰(zhàn)部分

      在這個(gè)網(wǎng)站中,提供了一些連接場(chǎng)景下的代碼模板

      UVM TLM Example

      3.1 各component的連接結(jié)構(gòu)圖

      需要畫(huà)一張圖,畫(huà)一個(gè)大而全的圖

      3.2 代碼部分

      本文轉(zhuǎn)自 https://blog.csdn.net/weixin_48157494/article/details/151726600,如有侵權(quán),請(qǐng)聯(lián)系刪除。

      posted @ 2025-09-24 17:15  LeslieQ  閱讀(15)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 好爽好紧好大的免费视频| 97se亚洲综合自在线| 夜爽8888视频在线观看| 少妇人妻偷人精品免费| 在线 | 国产精品99传媒a| 日本无遮挡真人祼交视频| 99亚洲男女激情在线观看| aaa少妇高潮大片免费看| 国产精品日韩中文字幕| 久久精品亚洲精品国产色婷 | 国产无遮挡猛进猛出免费| 久久精品国产久精国产| 欧美巨大极度另类| 日韩av在线不卡一区二区| 一区二区三区AV波多野结衣| 五月婷婷久久中文字幕| 欧洲精品码一区二区三区| 亚洲有无码中文网| 欧美日本精品一本二本三区| 国产自产一区二区三区视频| 日本熟妇色xxxxx日本免费看| 性欧美丰满熟妇xxxx性| 深夜av在线免费观看| 四虎影视一区二区精品| 国偷自产一区二区三区在线视频 | 亚洲综合91社区精品福利| 精品亚洲无人区一区二区| 成在线人永久免费视频播放| 丰满高跟丝袜老熟女久久| 婷婷丁香五月深爱憿情网| 欧美丰满熟妇性xxxx| 真人性囗交视频| 国精产品一品二品国精在线观看| 日韩国产中文字幕精品| 欧美伦费免费全部午夜最新| 四虎永久地址www成人| 亚洲国产精品人人做人人爱| 欧美精品日韩精品一卡| 亚洲欧美日韩高清一区二区三区| 亚洲男人第一无码av网站| 国产精品久久国产精品99 gif|