uvm 中的信息報告機制相對來講比較簡單,功能上來講主要分爲兩部分:
第一經過ID對component的信息報告冗餘級別進行控制,針對每一個冗餘級別進行不一樣的行爲控制。這部分工做主要由uvm_report_hander來實現:
主要涉及到的方法有get_report_verbosity_level(severity, id)/get_report_action(severity,id) == uvm_action'(UVM_NO_ACTION)
第二是對message進行格式化的輸出,這部分工做主要由uvm_report_server來實現
主要涉及到的方法有message_compose
咱們經過一個`uvm_error宏的執行進行分析,
`uvm_error(「driver」, 「the config object is null」)
這是一個在TB中調用的uvm宏,主要接收兩個參數 ID和要打印的MSG,這個宏在 uvm_message_defines.svh中進行定義,具體定義以下:
140 `define uvm_error(ID,MSG) \
141 begin \
142 if (uvm_report_enabled(UVM_NONE,UVM_ERROR,ID)) \
143 uvm_report_error (ID, MSG, UVM_NONE, `uvm_file, `uvm_line); \
144 end
首先調用的是uvm_report_enabled函數,主要目的是爲了檢查這個message是否容許輸出。這個函數有兩個版本,
假如是在一
個 component中調用uvm_error 宏的話,那麼使用的是這個 component本身的函數,
而這個函數是在uvm_report_object中定義的:
447 function int uvm_report_enabled(int verbosity,
448 uvm_severity severity=UVM_INFO, string id="");
449 if (get_report_verbosity_level(severity, id) < verbosity || //檢查對應severity,id的verbosity(冗餘級別)是否大於容許輸出的verbosity
450 get_report_action(severity,id) == uvm_action'(UVM_NO_ACTION)) //檢查對應severity,id的action是不是UVM_NO_ACTION
451 return 0;
452 else
453 return 1;
454 endfunction
假如是在一個 sequence 中或者是一個派生自 uvm_object 的類中使用這個宏的
話,調用的是全局的函數
115 function bit uvm_report_enabled (int verbosity,
116 uvm_severity severity=UVM_INFO, string id="");
117 uvm_root top;
118 top = uvm_root::get();
119 return top.uvm_report_enabled(verbosity,severity,id);
120 endfunction
get_report_verbosity_level 的定義以下:
m_rh 是一個 uvm_report_handler 類型的變量,它會在每一個 component 實例化的
時候被實例化,也就是說,每一個 component 對應一個 m_rh,此變量用於記錄這個
component 的一些報告信息,
如是否單獨對此 component 設置了報告冗餘度級別
(verbosity_lever) 。 get_report_verbosity_level 這個函數最終調用的是
uvm_report_handler的get_verbosity_level函數。
81 class uvm_report_object extends uvm_object;
82
83 uvm_report_handler m_rh;
…
90 function new(string name = "");
91 super.new(name);
92 m_rh = new();
93 endfunction
…
413 function int get_report_verbosity_level(uvm_severity severity=UVM_INFO, string id="");
414 return m_rh.get_verbosity_level(severity, id);
415 endfunction
…
539 endclas
下面簡單的分析一下在uvm_report_handler中用到的get_verbosity_level函數,咱們能夠從中學到一些對數組的控制方式:
55 class uvm_report_handler;
…
236 function int get_verbosity_level(uvm_severity severity=UVM_INFO, string id="" );
237
238 uvm_id_verbosities_array array;
239 if(severity_id_verbosities.exists(severity)) begin //首先判斷severity_id_verbosities(聯合數組,索引就是severity)中是否存在與serverity對應的記錄
240 array = severity_id_verbosities[severity]; //這個聯合數組返回的是一個uvm_id_verbosities_array,而這個array是uvm_pool的一個實例,
241 if(array.exists(id)) begin //這個uvm_id_verbosities_array的索引就是對應的message_id,而內容則是這個message_id的冗餘整數
242 return array.get(id); //如今的問題是,這個severity_id_verbosities在哪裏被寫入??
243 end
244 end
245
246 if(id_verbosities.exists(id)) begin //id_verbosities是一個uvm_id_verbosities_array類型的變量
247 return id_verbosities.get(id); //索引就是對應的message_id,而內容則是這個message_id的冗餘整數
248 end //一樣的問題,這個id_verbosities在什麼時候被寫入??
249
250 return m_max_verbosity_level;
251
252 endfunction
…
622 endclass : uvm_report_handle
對uvm_action和file handle的處理跟get_verbosity_level相相似,這裏就再也不進行分析,如今咱們分析在上面代碼分析中提到的兩個問題:
1. 這個severity_id_verbosities在哪裏被寫入?咱們直接分析uvm_report_handler的code,由於前面提到了,這部分工做是有handler來實現和管理的:
function void set_severity_id_verbosity(uvm_severity severity,
string id,
int verbosity);
if(!severity_id_verbosities.exists(severity))
severity_id_verbosities[severity] = new;
severity_id_verbosities[severity].add(id,verbosity);
endfunction
2. id_verbosities在什麼時候被寫入?
function void set_id_verbosity(input string id, input int verbosity);
id_verbosities.add(id, verbosity);
endfunction
分析上面的代碼能夠知道這裏面set_severity_id_verbosity 要比set_id_verbosity的優先級要高。
咱們前面說過,對message進行格式化的輸出,這部分工做主要由uvm_report_server來實現,因此uvm_report_error通過傳遞,最終會調用uvm_report_server中的report函數,這裏面須要提一下的是uvm_report_server是單實例的,在這裏重申一下uvm_report機制幾個類之間的關係,
report—object和report_handler的關係是一 一對應的,固然也能夠多個report_object對應一個report_handler(set_report_handler).handler到server的關係是多對一。
243 virtual function void report(
244 uvm_severity severity,
245 string name,
246 string id,
247 string message,
248 int verbosity_level,
249 string filename,
250 int line,
251 uvm_report_object client
252 );
253 string m;
254 uvm_action a;
255 UVM_FILE f;
256 bit report_ok;
257 uvm_report_handler rh;
258
259 rh = client.get_report_handler(); // 再次拿到uvm_component的uvm_report_hander的實例指針,目的是爲了後面再次進行uvm_report_enabled檢查,以及拿到在uvm_report_handler中的file_handle
260
261 // filter based on verbosity level
262
273 f = rh.get_file_handle(severity, id);
274
275 // The hooks can do additional filtering. If the hook function
276 // return 1 then continue processing the report. If the hook
277 // returns 0 then skip processing the report.
278
279 if(a & UVM_CALL_HOOK)
280 report_ok = rh.run_hooks(client, severity, id,
281 message, verbosity_level, filename, line); //調用run_hooks函數再次確認是否進行打印信息,run_hooks在uvm_report_handler中進行定義,調用uvm_report_object中定義的report_info_hook/report_warning_hook/report_error_hook/report_fatal_hook函數,能夠在繼承uvm_component的時候對這些hook進行重載,今兒實現對message的控制。
282 else
283 report_ok = 1;
285 if(report_ok)
286 report_ok = uvm_report_catcher::process_all_report_catchers( //這是一個uvm_callback類,
它的主要用處就是在真正
的打印信息以前能夠再次控制要打印的信息,每一個uvm_catcher都要實現一個catch的函數!
287 this, client, severity, name, id, message,
288 verbosity_level, a, filename, line);
289
290 if(report_ok) begin
291 m = compose_message(severity, name, id, message, filename, line);
292 process_report(severity, name, id, message, a, f, filename,
這個是在uvm_catcher中的process_report_catcher函數:
local function int process_report_catcher();
action_e act;
act = this.catch();
if(act == UNKNOWN_ACTION)
this.uvm_report_error("RPTCTHR", {"uvm_report_this.catch() in catcher instance ", this.get_name(), " must return THROW or CAUGHT"}, UVM_NONE, `uvm_file, `uvm_line);
if(m_debug_flags & DO_NOT_MODIFY) begin
m_modified_severity = m_orig_severity;
m_modified_id = m_orig_id;
m_modified_verbosity = m_orig_verbosity;
m_modified_action = m_orig_action;
m_modified_message = m_orig_message;
end
if(act == CAUGHT && !(m_debug_flags & DO_NOT_CATCH)) begin
return 0;
end
return 1;
endfunction