1、狀態(tài)模式
狀態(tài)模式是一種行為設(shè)計(jì)模式, 讓你能在一個(gè)對(duì)象的內(nèi)部狀態(tài)變化時(shí)改變其行為, 使其看上去就像改變了自身所屬的類一樣。
在RTL中可能存在復(fù)雜的有限狀態(tài)機(jī)FSM,在任何一個(gè)特定狀態(tài)中, RTL的行為都不相同, 且可從一個(gè)狀態(tài)切換到另一個(gè)狀態(tài)。不過(guò), 根據(jù)當(dāng)前狀態(tài), RTL可能會(huì)切換到另外一種狀態(tài), 也可能會(huì)保持當(dāng)前狀態(tài)不變。這些數(shù)量有限且預(yù)先定義的狀態(tài)切換規(guī)則被稱為轉(zhuǎn)移。
為了對(duì)RTL FSM進(jìn)行建模,狀態(tài)設(shè)計(jì)模式建議將每個(gè)狀態(tài)的行為抽象成一個(gè)類,狀態(tài)之間的切換相當(dāng)于就是類對(duì)象的切換。主要可包括以下幾個(gè)組件:
Context:它并不會(huì)自行實(shí)現(xiàn)所有行為, 而是會(huì)保存一個(gè)指向表示當(dāng)前狀態(tài)的狀態(tài)對(duì)象的引用, 且將所有與狀態(tài)相關(guān)的工作委派給該對(duì)象。
State:所有狀態(tài)類的基類,所有狀態(tài)類都必須遵循同樣的接口, 而且context必須僅通過(guò)state提供的接口函數(shù)與這些對(duì)象進(jìn)行交互。
Concrete States:會(huì)自行實(shí)現(xiàn)特定于狀態(tài)的方法。為了避免多個(gè)狀態(tài)中包含相似代碼, 你可以提供一個(gè)封裝有部分通用行為的中間抽象類。狀態(tài)對(duì)象可存儲(chǔ)對(duì)于上下文對(duì)象的反向引用。狀態(tài)可以通過(guò)該引用從上下文處獲取所需信息, 并且能觸發(fā)狀態(tài)轉(zhuǎn)移。
下圖為狀態(tài)設(shè)計(jì)模式在FSM中應(yīng)用的一個(gè)UML類圖。
2、參考代碼
狀態(tài)設(shè)計(jì)模式的參考代碼如下:
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
?模擬測(cè)試代碼如下:
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
?