構(gòu)深度解析:從組件創(chuàng)建到phase調(diào)度與實戰(zhàn)應用)
從事數(shù)字IC驗證的朋友應該都對著UVM那套復雜的類層次關(guān)系頭疼過。翻開任何一本UVM教材前面幾章一定會畫那張經(jīng)典的UVM樹形結(jié)構(gòu)圖從uvm_top開始往下掛著uvm_test、uvm_env、uvm_agent、uvm_scoreboard……初看時覺得不過是幾個框框幾條線等真到自己動手搭平臺的時候才發(fā)現(xiàn)這張圖里的每一個節(jié)點都牽扯著組件創(chuàng)建的順序、phase執(zhí)行的先后、TLM端口的連接方式任何一環(huán)理解不到位編譯能過仿真跑起來就是一片紅。這個系列的“待更”標題正好戳中了很多驗證工程師的痛點到底該怎么理解并高效使用這棵Hierarchy樹而不是被它牽著鼻子走這期內(nèi)容我不打算把UVM的用戶手冊再抄一遍。我想從一個實際搭建驗證平臺的角度把這棵樹的來龍去脈、每個節(jié)點角色的實際意義、以及樹形結(jié)構(gòu)對仿真調(diào)度產(chǎn)生的真實影響掰開揉碎了講清楚。無論你是剛接觸UVM的學生還是在項目里被env套env搞到頭大的在職工程師這篇文章應該都能提供一些不一樣的視角。1. 為什么UVM平臺必須是一棵樹很多初學者會問一個很本質(zhì)的問題UVM組件之間明明可以通過指針隨便指來指去為什么非要搞出一個 Hierarchical 的樹狀結(jié)構(gòu)直接new幾個對象互相connect一下不行嗎先給結(jié)論從純功能的層面講確實可以。但從驗證平臺的可維護性、可重用性和執(zhí)行控制的角度講沒有層級關(guān)系的平臺就是一場災難。1.1 樹形結(jié)構(gòu)是phase機制的地基UVM最核心的機制之一是phase自動執(zhí)行也就是那套從build_phase到report_phase的自動調(diào)度流程。這套機制能跑起來前提是UVM能夠知道當前環(huán)境里一共有哪些組件每個組件屬于誰以及它們之間的父子關(guān)系。只有把這些信息組織成樹UVM的phase控制器才能從根節(jié)點出發(fā)自上而下地調(diào)用所有節(jié)點的build_phase再自下而上地執(zhí)行connect_phase保證整個平臺的組件都在正確的時間點被創(chuàng)建和連接。如果組件之間是散落的、無組織的那么UVM的phase控制器就完全失去了用武之地。你得自己在代碼里手動控制每個模塊的創(chuàng)建時機和reset信號的拉起順序這等于拋棄了UVM最核心的調(diào)度能力回到了Verilog testbench那套“誰在前面寫誰先執(zhí)行”的老路上去。1.2 樹形結(jié)構(gòu)提供服務(wù)而不僅僅是存儲Hierarchy樹上的每一個節(jié)點都自帶一套完整的“服務(wù)窗口”。最典型的就是uvm_component底層的get_full_name()、get_parent()、get_child()、get_children()等方法。這套接口對調(diào)試和通用組件的開發(fā)極其重要。舉個例子我在環(huán)境里放了三個完全相同的agent分別接三個不同的接口。如果想把三個agent內(nèi)部的sequencer都拿到test層來使用你當然可以在env里手動做三個端口把他們引出來但更優(yōu)雅的做法是利用uvm_top的find方法通過uvm_top.find(*.env.agent[2].sqr)這種路徑索引的方式直接拿到對應的sequencer指針。這種能力完全依賴于樹形結(jié)構(gòu)而且是層次越深、結(jié)構(gòu)越復雜這種基于路徑的訪問方式就越顯優(yōu)勢。1.3 樹結(jié)構(gòu)決定組件是否“可見”在UVM中組件必須掛在樹上才會被UVM的域通行機制field automation和工廠機制factory正常管理。比如你只是在某個類的構(gòu)造函數(shù)里new了一個uvm_component子類而沒有把它add到某個父節(jié)點下面那它在UVM的視角里是不存在的。體現(xiàn)在實際調(diào)試中你print樹形結(jié)構(gòu)的時候看不到它phase的build_phase也不會執(zhí)行到它甚至連它的uvm_info打印信息格式都不一樣。所以本質(zhì)上看UVM將組件的生命周期管理和調(diào)度能力都建立在樹的拓撲結(jié)構(gòu)之上。理解了這一點你就會明白創(chuàng)建組件時“掛在哪個節(jié)點下面”不是隨便寫的它直接決定了這個組件的功能角色和服務(wù)的范圍。2. 從uvm_top到testcase看清楚你的樹根和樹枝我們平時看樹的示意圖通常是從uvm_top往下畫。uvm_top是UVM內(nèi)置的根節(jié)點相當于整棵樹的root。它往往是被隱式創(chuàng)建的你不需要也不應該手動去new一個uvm_top。2.1 樹根uvm_top的隱藏屬性uvm_top繼承自uvm_root它本質(zhì)上也是一個component只不過被UVM自動實例化了。所有的uvm_component子類在創(chuàng)建的時候如果找不到合適的parentUVM會默認把它們掛到uvm_top下面。這里有一個很實用的技巧在運行仿真的時候UVM會通過uvm_top管理全局的run_test()調(diào)用。我們在testbench頂層通常寫這么一行initial begin run_test(); end這行的作用是讓UVM根據(jù)UVM_TESTNAME的傳入?yún)?shù)結(jié)合factory機制創(chuàng)建對應的test實例。而test實例創(chuàng)建時如果沒有指定parent就自動掛在了uvm_top下。所以uvm_top是整個樹的根test就成了樹根上的第一個大樹枝。2.2 主干樹枝test、env、agent我們常見的平臺結(jié)構(gòu)從uvm_top往下數(shù)依次是uvm_test整棵樹的控制分支唯一一個由外部命令決定創(chuàng)建哪個的節(jié)點。uvm_env被測設(shè)計(DUT)的驗證環(huán)境屬于test的子節(jié)點通常一個test對應一個或者多個env。uvm_agent環(huán)境內(nèi)的功能分支一個env下面可以掛著多個agent分別對應不同的接口協(xié)議如APB、AXI、I2C。agent可以配置為active模式或passive模式?jīng)Q定是否自動創(chuàng)建driver和sequencer。uvm_scoreboard數(shù)據(jù)比對和檢查的分支比分對邏輯復雜時可以拆出多個reference model和checker。uvm_subscriber被動監(jiān)聽分支典型的用法是掛到analysis port上收集覆蓋率或做監(jiān)控。每一條從uvm_top到葉子節(jié)點的路徑都形成了一條完整的組件訪問鏈。2.3 葉子節(jié)點一切的歸宿實際操作中葉子節(jié)點通常是那些不包含任何子組件的類比如uvm_driver從sequencer拿sequence_item轉(zhuǎn)換成接口上的時序信號。uvm_monitor監(jiān)測接口信號打包成transaction并發(fā)送出去。uvm_sequencer管理sequence的仲裁和生成流程。這些葉子節(jié)點是真正干活的角色。它們不關(guān)心自己在樹上的具體深度但會通過get_full_name()獲得如uvm_test_top.env.agent[0].driver這樣的完整路徑這對波形窗口里查看信號、日志中定位打印位置極其有用。3. 樹的構(gòu)建過程build_phase如何自上而下地長出一棵樹理解了樹的形狀重點就來了這么復雜的一棵樹到底是什么時候、以什么順序被一點點搭建出來的答案就是build_phase。3.1 build_phase的特殊性function phaseUVM的phase分為function phase和task phasebuild_phase屬于function phase而且在所有phase中是唯一一個自上而下執(zhí)行的phase。所謂“自上而下”是指從uvm_top開始先執(zhí)行test的build_phase然后執(zhí)行test下面所有env的build_phase如果存在多個則按創(chuàng)建順序再依次往下走直到執(zhí)行完所有葉子節(jié)點的build_phase。為什么非要自上而下因為父節(jié)點需要在build_phase中create它的子組件。如果父節(jié)點還沒構(gòu)建完成子組件就不存在自然無法繼續(xù)往下走。這個邏輯非常樸素卻決定了整個UVM平臺的初始化策略。3.2 創(chuàng)建組件的核心一行type_id::create在build_phase里最常寫的語句是my_agent my_agent::type_id::create(my_agent, this)。這句話背后做的事情很多人可能沒細想過。這一行調(diào)用了UVM的工廠機制和創(chuàng)建機制。::create內(nèi)部會通過factory查表決定實際實例化的對象類型這為后續(xù)的override操作提供了基礎(chǔ)然后調(diào)用new(my_agent, this)把當前組件作為父節(jié)點完成建樹操作。this參數(shù)至關(guān)重要如果沒有這個參數(shù)組件就會被掛到uvm_top下導致整棵樹的結(jié)構(gòu)錯亂。3.3 頂層設(shè)置is_active UVM_ACTIVE的意義在agent的build_phase中我們經(jīng)常會寫這樣的條件判斷if (is_active UVM_ACTIVE) begin driver driver::type_id::create(driver, this); sequencer sequencer::type_id::create(sequencer, this); end monitor monitor::type_id::create(monitor, this);這段代碼充分體現(xiàn)了樹形結(jié)構(gòu)的構(gòu)建策略agent在同一層次上可以根據(jù)配置參數(shù)決定是否掛上driver這個分支。如果配置為passive模式只需要監(jiān)控、不需要激勵那么agent下面就不會有driver節(jié)點。樹的結(jié)構(gòu)因此變得靈活可以在不同測試場景中動態(tài)調(diào)整。4. connect_phase與樹上的橫向連接build_phase負責把樹上的節(jié)點建立起來。但節(jié)點之間如果只是擺在那里相互不通信那這臺驗證平臺就是一堆沒有靈魂的死組件。組件與組件之間的通信依賴的是connect_phase。4.1 自下而上的connect順序與build_phase相反connect_phase是自下而上執(zhí)行的。先連接葉子節(jié)點的端口再往上層連接。這個順序的設(shè)置是為了保證在父節(jié)點嘗試連接子節(jié)點的port時子節(jié)點的port已經(jīng)完全創(chuàng)建好并且可以被訪問。比如env中的connect_phase里會執(zhí)行agent.monitor.item_port.connect(scoreboard.analysis_imp)。如果scoreboard或者agent內(nèi)部的monitor還沒有執(zhí)行完build_phase這個connect操作就會失敗。UVM通過自下而上的phase順序巧妙地避開了這種競爭問題。4.2 TLM端口連接如何影響樹形結(jié)構(gòu)的視覺很多剛接觸UVM的人會被uvm_analysis_port、uvm_analysis_imp、uvm_blocking_put_port等一連串TLM端口弄得暈頭轉(zhuǎn)向。從樹形結(jié)構(gòu)的角度看這些端口連接其實是把樹上原本平行的兩個分支在節(jié)點之間拉起了“橫向的梁”。樹形結(jié)構(gòu)本身是縱向的父子關(guān)系而TLM連接是節(jié)點間的橫向通信通道。邏輯上看這個環(huán)境可能長這樣agent的monitor抓到數(shù)據(jù)通過analysis port發(fā)給scoreboard和reference model。reference model處理完又發(fā)給scoreboard。如果在紙上畫拓撲關(guān)系這樹的分支之間是有數(shù)據(jù)流箭頭的。4.3 一個常見的錯誤attempt to connect port after simulation has ended我在實戰(zhàn)中踩過這樣一個坑在test的build_phase里試圖連接env內(nèi)部組件的TLM端口。比如function void my_test::build_phase(uvm_phase phase); super.build_phase(phase); env env::type_id::create(env, this); env.agent.monitor.connect(env.scoreboard.analysis_imp); endfunction這樣寫會報一個奇怪的錯誤“attempt to connect port after simulation has ended”或者“connection can only be made from a component”。原因很好理解build_phase階段env內(nèi)部的子組件agent、scoreboard都還沒創(chuàng)建此時訪問env.agent只會返回null。等env自己執(zhí)行build_phase的時候這些子組件才被new出來。所以connect的操作必須放在合適層次組件的connect_phase里而不是隨便哪個階段都能連。這個原則也是在理解了樹的構(gòu)建順序后自然而然得出來的結(jié)論。5. phase執(zhí)行順序?qū)浣Y(jié)構(gòu)的影響避免踩進調(diào)度誤區(qū)UVM phase機制和樹形結(jié)構(gòu)的關(guān)系值得單獨拿一個章節(jié)來講。5.1 樹的深度決定不同phase到達葉子節(jié)點的時間差我們知道UVM擁有多個運行phase如reset_phase、configure_phase、main_phase、shutdown_phase等。這些task phase是分叉執(zhí)行的默認情況下是并行運行的。但是樹形結(jié)構(gòu)的存在使得這些phase的執(zhí)行在樹的每個節(jié)點上都有獨立的進程。例如當reset_phase開始時uvm_top的reset_phase先執(zhí)行然后依次向下調(diào)度。由于task phase是可以消耗仿真時間delay的如果A分支在reset_phase里delay了100ns而B分支在reset_phase只delay了10ns那么B分支會先進入configure_phaseA分支還在reset_phase里耗著。這時整個環(huán)境的phase執(zhí)行狀態(tài)在樹的不同層級上是不同步的。這解釋了為什么很多跨組件的同步問題那么難查你以為是IDLE狀態(tài)沒拉對實際是不同分支phase進度不一致導致的。特別是當樹很深、分支很多時這種時間差會被放大。5.2 phase同步機制用barrier來收斂UVM提供了phase的同步機制當一個分支的phase提前結(jié)束時它會等待其他分支完成這就是phase barrier技術(shù)。默認情況下run_phase是全局同步的而其他12個task phase是分叉的。如果你不希望各agent互相等待可以保留分叉執(zhí)行如果希望所有組件都齊步走可以用phase.stall()或者設(shè)置uvm_phase::m_phase_clocks等底層機制。不過一般項目用到這個層面的不多。5.3 樹結(jié)構(gòu)中的“孤兒節(jié)點”debug技巧排查問題時經(jīng)常有一個很實用的手段打印整棵樹。在test中調(diào)用uvm_top.print_topology()或者factory.print()都可以看到當前樹上所有節(jié)點的名字、full_name、type_name和id等信息。initial begin run_test(); end function void my_test::start_of_simulation_phase(uvm_phase phase); uvm_top.print_topology(); endfunction你會清晰地看到類似下面的輸出Name Type Size Value ------------------------------------------------------------ uvm_test_top my_test - 1845 env my_env - 1921 agent my_agent - 1977 sequencer uvm_sequencer #(my_transaction) ... driver my_driver - 2100 monitor my_monitor - 2156 scoreboard my_scoreboard - 2203 analysis_imp uvm_analysis_imp #(my_transaction)...看到這個你就能一眼定位環(huán)境是哪里接錯了哪個組件沒有掛到預期的父節(jié)點下面。在項目早期每次build完先打印一下拓撲可以避免大量后期調(diào)試的麻煩。6. 寄存器模型在樹結(jié)構(gòu)中的位置與特殊設(shè)計熱詞里提到了“uvm寄存器模型鏡像值”這是UVM驗證中一個繞不開的高級話題。寄存器模型在Hierarchy樹中有著特殊的地位。6.1 reg_model是component嗎很多人會混淆。標準UVM中uvm_reg_block、uvm_reg、uvm_reg_field等類是從uvm_object繼承的而不是uvm_component。它們并不是樹上的節(jié)點不會參與phase的自動執(zhí)行。它們依賴一個uvm_reg_predictor和uvm_reg_adapter來完成與總線的通信。但是uvm_reg_predictor本身是一個component它在樹上占據(jù)一個分支。通常這個predictor被掛載到agent下面通過monitor的analysis port接收總線操作然后更新寄存器模型的鏡像值mirror value。6.2 鏡像值更新的兩種路徑predictor與manual update鏡像值是什么簡單講就是寄存器模型認為當前硬件寄存器中保存的值。為了讓這個值保持正確需要持續(xù)跟蹤總線上對該寄存器的讀寫操作。UVM提供了兩條路徑來更新鏡像值通過reg_model.mirror()主動讀取寄存器值然后更新本地鏡像。通過uvm_reg_predictor被動監(jiān)測總線操作實時刷新鏡像。后者是推薦做法。因為mirror()是阻塞操作要在總線上發(fā)起實際讀取在某些場景下會影響被測設(shè)計的行為。而predictor方式是非侵入的它監(jiān)聽APB或AXI總線上的write/read操作計算出新的鏡像值調(diào)Xpredict更新。6.3 樹結(jié)構(gòu)上的寄存器集成實戰(zhàn)在平臺上集成寄存器模型時樹結(jié)構(gòu)的作用體現(xiàn)在兩個地方第一reg_model需要配置一個map指定基地址和訪問屬性。這個map在env的build_phase中創(chuàng)建通過reg_model.default_map create_map(...)實現(xiàn)。然后需要在agent內(nèi)部創(chuàng)建一個uvm_reg_adapter定義寄存器讀寫到總線sequence_item的轉(zhuǎn)換規(guī)則。第二在env的connect_phase中需要將寄存器模型與predictor連接reg_model.default_map.set_sequencer(agent.sequencer, agent.adapter); reg_model.default_map.set_auto_predict(0); agent.monitor.item_port.connect(predictor.bus_in); predictor.map reg_model.default_map; predictor.adapter agent.adapter;這一套連接其實就是在已有的樹的縱向結(jié)構(gòu)上把寄存器模型的橫向網(wǎng)絡(luò)織進去。樹的縱深給了模型訪問的路徑橫向TLM連接給了數(shù)據(jù)流通道。6.4 關(guān)于鏡像值一個實戰(zhàn)經(jīng)驗我在實際項目中遇到過鏡像值與硬件值不一致的情況。排查下來發(fā)現(xiàn)是predictor沒有正確連接到monitor的analysis port或者adapter中的reg2bus和bus2reg函數(shù)寫錯了字節(jié)偏移。特別是對于帶byte-enable的寫操作如果在bus2reg里沒有正確解析wstrb信號鏡像值很容易被寫成全F或全0。建議在集成寄存器模型時先寫一個“讀寫回環(huán)”的測試用例驗證所有寄存器的讀寫和鏡像更新路徑都通暢后再繼續(xù)其他用例的開發(fā)。7. 樹形結(jié)構(gòu)中的多序列調(diào)度問題樹形結(jié)構(gòu)的影響還遠不止組件構(gòu)建。在葉子節(jié)點sequencer這里樹形結(jié)構(gòu)的父節(jié)點——也就是sequence的執(zhí)行環(huán)境——會深刻影響多個sequence之間的調(diào)度方式。7.1 sequence_item在sequencer上排隊sequencer是UVM平臺上最繁忙的葉子節(jié)點之一。它接收到來自各個sequence的item后需要按照仲裁規(guī)則決定哪個item進入driver。在樹形結(jié)構(gòu)中sequencer屬于某個agent的下面但多個sequence可以被start在同一個sequencer上。seq1.start(env.agent.sequencer); seq2.start(env.agent.sequencer);當這兩條sequence同時啟動時它們產(chǎn)生的item會送到同一個sequencer的仲裁隊列中。UVM提供了一套仲裁機制uvm_sequencer_arb_mode可以設(shè)置為UVM_SEQ_ARB_FIFO、UVM_SEQ_ARB_WEIGHTED、UVM_SEQ_ARB_RANDOM等。默認情況下FIFO模式即可滿足大多數(shù)場景需求。7.2 樹結(jié)構(gòu)影響sequence的嵌套執(zhí)行有些場景下sequence需要嵌套執(zhí)行比如一個“寫32筆數(shù)據(jù)”的sequence內(nèi)部調(diào)用了另一個“寫單筆數(shù)據(jù)”的sequence。如果這兩個sequence是同一個類型使用p_sequencer訪問當前sequencer的成員就能拿到需要的數(shù)據(jù)。class write_burst_seq extends uvm_sequence #(my_transaction); uvm_object_utils(write_burst_seq) task body(); write_one_seq single_seq; repeat(32) begin single_seq write_one_seq::type_id::create(single_seq); single_seq.start(m_sequencer); end endtask endclass這里面start(m_sequencer)實際上是在把新的sequence掛到當前sequencer這棵子樹的調(diào)用上下文中執(zhí)行。如果m_sequencer傳遞錯誤比如傳成了nullsequence就無法找到目標driver。7.3 sequencer在樹上的路徑與TLM端口對應在多agent環(huán)境下樹形路徑的重要性更加突出。比如你想讓一個sequence只跑到APB agent的sequencer上你必須在sequence的body里通過p_sequencer間接引用正確分支上的sequencer。class apb_write_seq extends uvm_sequence #(apb_transfer); uvm_object_utils(apb_write_seq) uvm_declare_p_sequencer(apb_sequencer) task body(); apb_transfer tr; uvm_do_with(tr, {tr.addr 32h0; tr.data 32hdead_beef;}) endtask endclass當你在test中調(diào)用apb_write_seq.start(env.apb_agent.sequencer)時這個sequence就只會作用于APB分支。樹結(jié)構(gòu)清晰路徑明確這段代碼的可讀性和可維護性都會非常好。8. 關(guān)于樹形結(jié)構(gòu)的幾個反直覺實戰(zhàn)結(jié)論最后分享幾個我在實際項目里總結(jié)出來的、可能跟“教科書式UVM”不太一樣的觀點。8.1 樹不一定要原封不動地套模板很多人一上來就標準三件套test、env、agent。但在一些輕量級的IP驗證環(huán)境中根本沒有必要把agent單獨抽出來。如果只有一個接口直接在env里建driver、monitor、sequencer代碼量反而更少結(jié)構(gòu)也更扁平。UVM的核心是可控性和可重用性如果你的項目就是一次性驗證那么過深的樹結(jié)構(gòu)反而增加了無意義的維護成本。8.2 深樹比寬樹更難調(diào)試我見過有人把環(huán)境搭得特別深test - env - sub_env - sub_sub_env - agent - collector - monitor。當調(diào)試時任何一個葉子節(jié)點打出來的報告首先映入眼簾的就是那長長的層次前綴一個打印信息從左邊出到右邊才看到內(nèi)容。而且update路徑變長build_phase時間也相應增加。所以我一般建議環(huán)境層次保持在4層以內(nèi)test - env - agent - driver/sequencer/monitor超過5層就要考慮是不是設(shè)計過度了。8.3 print_topology是調(diào)試的第一利器任何一次環(huán)境結(jié)構(gòu)重大修改后先跑一個最簡單的test掛到end_of_elaboration_phase或者start_of_simulation_phase里打印整個拓撲結(jié)構(gòu)。掃一眼樹形輸出看有沒有預期外的節(jié)點或孤立的組件。這一步15秒的時間能省下接下來可能一整天的定位時間。8.4 別忽略了run_test入口的參數(shù)傳遞在testbench中run_test()是不帶參數(shù)的需要靠UVM_TESTNAME指定test名。但如果你直接寫成run_test(my_test)雖然能跑但不利于在回歸測試中批量切換用例。通常我們會在Makefile里設(shè)置UVM_TESTNAME變量例如TEST_NAME ? my_test RTL_SIM_OPT UVM_TESTNAME$(TEST_NAME) test_all: $(SIM_TOOL) $(RTL_SIM_OPT) -f filelist.f ...這種情況下樹根節(jié)點的名字默認是uvm_test_top如果你依賴根節(jié)點的名字做某些路徑訪問要注意保持一致。9. 關(guān)于樹形結(jié)構(gòu)優(yōu)化與工具鏈的補充如果你用的仿真工具是VCS或Questa對于層次結(jié)構(gòu)的支持也有不少值得關(guān)注的功能點。比如在VCS中加-debug_accessall然后利用UVM的層次化調(diào)試命令在仿真運行中通過UVM命令提示符UVM command shell直接查詢樹上的節(jié)點uvm get config uvm print topology正確配置工具鏈可以讓樹形結(jié)構(gòu)的調(diào)試效率成倍提升。還有一點在Questasim中可以使用uvm_coreseeker機制查找節(jié)點它使用模式匹配算法支持通配符。uvm_top.find(*.env.*.monitor)這種查找方式特別適合在多agent環(huán)境下快速定位某個監(jiān)控器。寫在最后的幾點個人體會關(guān)于Hierarchy樹形結(jié)構(gòu)其實還有一個很關(guān)鍵的心態(tài)問題。很多初學者喜歡把UVM的結(jié)構(gòu)理解為一種“必須遵守的軍規(guī)”但其實UVM給了開發(fā)者極大的自由。它允許你構(gòu)建任意深度、任意結(jié)構(gòu)的樹只要每個節(jié)點掛在合適的位置phase調(diào)度和TLM通信機制就能正常工作。我在項目中反復品味這棵樹之后最大的感受是樹形結(jié)構(gòu)不是UVM強加給用戶的負擔而是UVM為驗證平臺提供的一套“骨架生成系統(tǒng)”。它把組件的生命周期、通信關(guān)系、調(diào)度機制全部統(tǒng)一在了同一個框架里。只要你理解了樹的生長邏輯那么平臺的搭建、配置、調(diào)試甚至擴展都會變得順理成章。這個系列后續(xù)如果繼續(xù)更我想專門寫一篇關(guān)于TLM端口在不同樹分支之間如何優(yōu)雅地搬運數(shù)據(jù)以及序列(sequence)如何在sequencer這棵子樹上實現(xiàn)復雜的嵌套調(diào)度。各位如果對樹的某一層有具體疑問也歡迎在評論里一起討論。