1、狀態(tài)模式
狀態(tài)模式是一種行為設計模式, 讓你能在一個對象的內(nèi)部狀態(tài)變化時改變其行為, 使其看上去就像改變了自身所屬的類一樣。
在RTL中可能存在復雜的有限狀態(tài)機FSM,在任何一個特定狀態(tài)中, RTL的行為都不相同, 且可從一個狀態(tài)切換到另一個狀態(tài)。不過, 根據(jù)當前狀態(tài), RTL可能會切換到另外一種狀態(tài), 也可能會保持當前狀態(tài)不變。這些數(shù)量有限且預先定義的狀態(tài)切換規(guī)則被稱為轉(zhuǎn)移。
為了對RTL FSM進行建模,狀態(tài)設計模式建議將每個狀態(tài)的行為抽象成一個類,狀態(tài)之間的切換相當于就是類對象的切換。主要可包括以下幾個組件:
Context:它并不會自行實現(xiàn)所有行為, 而是會保存一個指向表示當前狀態(tài)的狀態(tài)對象的引用, 且將所有與狀態(tài)相關(guān)的工作委派給該對象。
State:所有狀態(tài)類的基類,所有狀態(tài)類都必須遵循同樣的接口, 而且context必須僅通過state提供的接口函數(shù)與這些對象進行交互。
Concrete States:會自行實現(xiàn)特定于狀態(tài)的方法。為了避免多個狀態(tài)中包含相似代碼, 你可以提供一個封裝有部分通用行為的中間抽象類。狀態(tài)對象可存儲對于上下文對象的反向引用。狀態(tài)可以通過該引用從上下文處獲取所需信息, 并且能觸發(fā)狀態(tài)轉(zhuǎn)移。
下圖為狀態(tài)設計模式在FSM中應用的一個UML類圖。
2、參考代碼
狀態(tài)設計模式的參考代碼如下:
typedef class fsm_context;
typedef class concrete_state1;
typedef class concrete_state2;
virtual class state;
??? pure virtual function int process1(fsm_context cnxt);
??? pure virtual function int process2(fsm_context cnxt);
endclass : state
class concrete_state1 extends state;
??? function int process1(fsm_context cnxt);
??????? $display("concrete_state1 : process1");
??????? if ( cnxt.change_state ) begin
??????????? concrete_state2 state2 = new();
??????????? $display("concrete_state1 change to concrete_state2");
??????????? cnxt.st = state2;
??????? end
??? endfunction : process1
??? function int process2(fsm_context cnxt);
??????? $display("concrete_state1 : process2");
??????? if ( cnxt.change_state ) begin
??????????? concrete_state2 state2 = new();
??????????? $display("concrete_state1 change to concrete_state2");
??????????? cnxt.st = state2;
??????? end
??? endfunction : process2
endclass : concrete_state1
class concrete_state2 extends state;
??? function int process1(fsm_context cnxt);
??????? $display("concrete_state2 : process1");
??????? if ( cnxt.change_state ) begin
??????????? concrete_state1 state1 = new();
??????????? $display("concrete_state2 change to concrete_state1");
??????????? cnxt.st = state1;
??????? end
??? endfunction : process1
??? function int process2(fsm_context cnxt);
??????? $display("concrete_state2 : process2");
??????? if ( cnxt.change_state ) begin
??????????? concrete_state1 state1 = new();
??????????? $display("concrete_state2 change to concrete_state1");
??????????? cnxt.st = state1;
??????? end
??? endfunction : process2
endclass : concrete_state2
class fsm_context;
??? state st;
??? function bit change_state();
??????? return 1; // for simplicity
??? endfunction : change_state
??? function void process_req1 (/*interface signals*/);
??????? st.process1(this /*, interface signals*/);
??? endfunction : process_req1
??? function void process_req2 (/*interface signals*/);
??????? st.process2(this /*, interface signals*/);
??? endfunction : process_req2
endclass : fsm_context
?模擬測試代碼如下:
fsm_context fsm_st = new();
fsm_st.st = concrete_state1::new();
fsm_st.process_req1();
fsm_st.process_req2();
使用Questasim仿真輸出日志如下:
| # concrete_state1 : process1
?| # concrete_state1 change to concrete_state2
?| # concrete_state2 : process2
?| # concrete_state2 change to concrete_state1
?