软件设计中,FSM(Finite-State Machine)分为3部分:状态(State),事件(Event),动作(Action)。
状态模式(State Pattern)是行为型(Behavioral)设计模式,将软件主机端的行为归类为各个状态,状态之间可以互相转化,每种状态的行为不相同;统一交给一个Context类型的模块负责调度各个状态的跳转;
硬件设计中的FSM,不仅是一种电路的描述工具,而且也是一种思想方法;数字逻辑本质上都可以归一化为FSM;RTL描述FSM可以归类为常用的几种方法,通常采用三段式的描述;
在我们的验证环境中,有时也需要一个组件专门负责FSM的建模;例如验证USB Device DUT时,验证环境需要模拟USB Host的行为;对于USB协议复杂的状态机,使用专门的FSM组件模拟,可以减少组件间的耦合;也可以将FSM组件的状态赋值到virtual interface上,通过波形协助debug;
并不是所有DUT模块中包含FSM,验证环境中就需要对应的FSM建模;RTL的硬件电路是cycle级的时序电路,采用FSM可以很好的描述算法运算;而验证环境都是事务级的基于事件的高级抽象模型,是否需要采用FSM根据验证环境而定;对于简单的设计,不需要模拟FSM;对于复杂的标准协议,VIP中都会采用FSM建模来完成,具有高内聚低耦合的好处。
Simple example
本篇对一个示例,分别使用两种方式来描述:
一个简单的FSM如下,分为4种状态;对于状态的跳转条件,本篇通过uvm_event类型的事件触发,验证环境中的实际情况可以是事件,某一个signal状态,或者if的判断等;不同状态下的Action,仅使用一句display代表,验证环境中的实际情况可以调用某一个task,对signal的驱动,或者调用其他组件的API等;仅做结构上的演示;
通过randsequence产生激励sequence,遍历状态机跳转条件;
classclient; state_machineFSM; uvm_event_poolevents_pool; uvm_eventto_idle,to_state_a,to_state_b,to_state_c; functionnew(); events_pool=uvm_event_pool::get_global_pool(); to_idle=events_pool.get("to_idle"); to_state_a=events_pool.get("to_state_a"); to_state_b=events_pool.get("to_state_b"); to_state_c=events_pool.get("to_state_c"); endfunction taskrand_simulate(); for(inti=0;i<2;i++) begin bit FLAG = 0; randsequence (stream) stream : first second third last; first : state_a; second : state_b {FLAG = 1;} | state_c; third : if (FLAG ==1) state_c else state_b; last : state_idle; state_idle: {`INTERVALTIME;to_idle.trigger();}; state_a : {`INTERVALTIME;to_state_a.trigger();}; state_b : {`INTERVALTIME;to_state_b.trigger();}; state_c : {`INTERVALTIME;to_state_c.trigger();}; endsequence end endtask ...... ......
use task
类state_machine包含四个状态的task;通过request_state_change函数实现状态跳转;每进入一个状态,对应一个线程,当跳出状态时,注意线程需要disable掉;
classstate_machine; typedefenum{ IDLE,STATE_A,STATE_B,STATE_C }state_t; uvm_event_poolevents_pool; uvm_eventto_idle,to_state_a,to_state_b,to_state_c; localstate_tcur_state; externfunctionnew(); externfunctionvoidstart(); externfunctionvoidrequest_state_change(state_tcur_state); externtaskdo_idle(); externtaskdo_state_a(); externtaskdo_state_b(); externtaskdo_state_c(); endclass functionstate_machine::new(); events_pool=uvm_event_pool::get_global_pool(); to_idle=events_pool.get("to_idle"); to_state_a=events_pool.get("to_state_a"); to_state_b=events_pool.get("to_state_b"); to_state_c=events_pool.get("to_state_c"); endfunction functionvoidstate_machine::start(); cur_state=IDLE; request_state_change(cur_state); endfunction functionvoidstate_machine::request_state_change(state_tcur_state); case(cur_state) IDLE:begin fork begin $display("Enter%sstate!",cur_state.name()); do_idle(); end join_none return; end STATE_A:begin fork begin $display("Enter%sstate!",cur_state.name()); do_state_a(); end join_none return; end STATE_B:begin fork begin $display("Enter%sstate!",cur_state.name()); do_state_b(); end join_none return; end STATE_C:begin fork begin $display("Enter%sstate!",cur_state.name()); do_state_c(); end join_none return; end default:begin $display("Enterunknowstate!"); $finish; end endcase endfunction taskstate_machine::do_idle(); state_tcur_state; $display("IDLE:nothingtodo! "); fork:disable_fork begin to_state_a.wait_trigger(); //$display("dosomething! "); cur_state=STATE_A; end join_any request_state_change(cur_state); endtask taskstate_machine::do_state_a(); state_tcur_state; $display("STATE_A:dosomething! "); fork:disable_fork begin to_state_b.wait_trigger(); //$display("dosomething! "); cur_state=STATE_B; end begin to_state_c.wait_trigger(); //$display("dosomething! "); cur_state=STATE_C; end join_any disablefork; request_state_change(cur_state); endtask taskstate_machine::do_state_b(); state_tcur_state; $display("STATE_B:dosomething! "); fork:disable_fork begin to_state_c.wait_trigger(); //$display("dosomething! "); cur_state=STATE_C; end begin to_idle.wait_trigger(); //$display("dosomething! "); cur_state=IDLE; end join_any disablefork; request_state_change(cur_state); endtask taskstate_machine::do_state_c(); state_tcur_state; $display("STATE_C:dosomething! "); fork:disable_fork begin to_state_b.wait_trigger(); //$display("dosomething! "); cur_state=STATE_B; end begin to_idle.wait_trigger(); //$display("dosomething! "); cur_state=IDLE; end join_any disablefork; request_state_change(cur_state); endtask
use Sate Pattern
采用状态模式的设计,每个状态继承于virtual class state,实现各自的do_something和request_state_change;state_machine通过宏REGISTER_STATE创建各个state实例;state_machine中forvever执行;状态模式和策略模式的实现类似,都是使用OOP的组合 + 多态实现;
virtualclassstate; state_machineFSM; uvm_event_poolevents_pool; uvm_eventto_idle,to_state_a,to_state_b,to_state_c; functionnew(); events_pool=uvm_event_pool::get_global_pool(); to_idle=events_pool.get("to_idle"); to_state_a=events_pool.get("to_state_a"); to_state_b=events_pool.get("to_state_b"); to_state_c=events_pool.get("to_state_c"); endfunction purevirtualtaskdo_something(); purevirtualtaskrequest_state_change(); endclass classstate_idleextendsstate; taskdo_something(); $display("STATE_IDLE:nothingtodo! "); endtask taskrequest_state_change(); state_tcur_state; fork:disable_fork begin to_state_a.wait_trigger(); //$display("dosomething! "); cur_state=STATE_A; end join_any FSM.set_state(cur_state); endtask endclass classstate_aextendsstate; taskdo_something(); $display("STATE_A:dosomething! "); endtask taskrequest_state_change(); state_tcur_state; fork:disable_fork begin to_state_b.wait_trigger(); //$display("dosomething! "); cur_state=STATE_B; end begin to_state_c.wait_trigger(); //$display("dosomething! "); cur_state=STATE_C; end join_any disablefork; FSM.set_state(cur_state); endtask endclass classstate_bextendsstate; taskdo_something(); $display("STATE_B:dosomething! "); endtask taskrequest_state_change(); state_tcur_state; fork:disable_fork begin to_state_c.wait_trigger(); //$display("dosomething! "); cur_state=STATE_C; end begin to_idle.wait_trigger(); //$display("dosomething! "); cur_state=STATE_IDLE; end join_any disablefork; FSM.set_state(cur_state); endtask endclass classstate_cextendsstate; taskdo_something(); $display("STATE_C:dosomething! "); endtask taskrequest_state_change(); state_tcur_state; fork:disable_fork begin to_state_b.wait_trigger(); //$display("dosomething! "); cur_state=STATE_B; end begin to_idle.wait_trigger(); //$display("dosomething! "); cur_state=STATE_IDLE; end join_any disablefork; FSM.set_state(cur_state); endtask endclass classstate_machine; localstatestate_m; statestate_pool[state_t]; functionvoidset_state(state_tstate); $display("Enter%sstate!",state.name()); state_m=state_pool[state]; endfunction functionvoidfsm_init(); `REGISTER_STATE(IDLE,idle) `REGISTER_STATE(A,a) `REGISTER_STATE(B,b) `REGISTER_STATE(C,c) this.set_state(STATE_IDLE); endfunction taskrun(); fsm_init(); foreverbegin state_m.do_something(); state_m.request_state_change(); end endtask endclass
note
state_machine中还可以加入reset stop函数控制FSM的更多行为;封装更多API供其他模块调用;加入assertion做基于cycle的条件判断;加入covergroup收集功能覆盖率;
审核编辑:刘清
-
RTL
+关注
关注
1文章
385浏览量
59710 -
UVM
+关注
关注
0文章
181浏览量
19142 -
状态机
+关注
关注
2文章
492浏览量
27484 -
fsm
+关注
关注
0文章
35浏览量
12815 -
DUT
+关注
关注
0文章
189浏览量
12344
原文标题:UVM设计模式 (九) 状态模式、Modelling Finite-State Machines in Testbench
文章出处:【微信号:数字芯片设计工程师,微信公众号:数字芯片设计工程师】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论