UVM设计模式之状态模式介绍

电子说

1.3w人已加入

描述

软件设计中,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等;仅做结构上的演示;

DUT

通过randsequence产生激励sequence,遍历状态机跳转条件;

 

class client;

   state_machine FSM;
   uvm_event_pool events_pool;
   uvm_event to_idle,to_state_a,to_state_b,to_state_c;

   function 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

   task rand_simulate(); 
      for (int i=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掉;

 

class state_machine;

   typedef enum {
      IDLE,STATE_A,STATE_B,STATE_C
   } state_t;

   uvm_event_pool events_pool;
   uvm_event to_idle,to_state_a,to_state_b,to_state_c;

   local state_t cur_state;

   extern function new();
   extern function void start();
   extern function void request_state_change(state_t cur_state);
   extern task do_idle();
   extern task do_state_a();
   extern task do_state_b();
   extern task do_state_c();

endclass

function state_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

function void state_machine::start();
   cur_state = IDLE;
   request_state_change(cur_state);
endfunction

function void state_machine::request_state_change(state_t cur_state);
   case(cur_state)
      IDLE:begin
         fork
            begin
               $display("Enter %s state!",cur_state.name());
               do_idle();
            end
         join_none
         return;
      end
      STATE_A:begin
         fork
            begin
               $display("Enter %s state!",cur_state.name());
               do_state_a();
            end
         join_none
         return;
      end
      STATE_B:begin
         fork
            begin
               $display("Enter %s state!",cur_state.name());
               do_state_b();
            end
         join_none
         return;
      end
      STATE_C:begin
         fork
            begin
               $display("Enter %s state!",cur_state.name());
               do_state_c();
            end
         join_none
         return;
      end
      default : begin
            $display("Enter unknow state!");
            $finish;
      end
   endcase
endfunction

task state_machine::do_idle();
   state_t cur_state;
   $display("IDLE : nothing to do!
");
   fork: disable_fork
      begin
         to_state_a.wait_trigger();
         //$display("do something!
");
         cur_state = STATE_A;
      end
   join_any
   request_state_change(cur_state);
endtask

task state_machine::do_state_a();
   state_t cur_state;
   $display("STATE_A : do something!
");
   fork: disable_fork
      begin
         to_state_b.wait_trigger();
         //$display("do something!
");
         cur_state = STATE_B;
      end
      begin
         to_state_c.wait_trigger();
         //$display("do something!
");
         cur_state = STATE_C;
      end
   join_any
   disable fork;
   request_state_change(cur_state);
endtask

task state_machine::do_state_b();
   state_t cur_state;
   $display("STATE_B : do something!
");
   fork: disable_fork
      begin
         to_state_c.wait_trigger();
         //$display("do something!
");
         cur_state = STATE_C;
      end
      begin
         to_idle.wait_trigger();
         //$display("do something!
");
         cur_state = IDLE;
      end
   join_any
   disable fork;
   request_state_change(cur_state);
endtask

task state_machine::do_state_c();
   state_t cur_state;
   $display("STATE_C : do something!
");
   fork: disable_fork
      begin
         to_state_b.wait_trigger();
         //$display("do something!
");
         cur_state = STATE_B;
      end
      begin
         to_idle.wait_trigger();
         //$display("do something!
");
         cur_state = IDLE;
      end
   join_any
   disable fork;
   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的组合 + 多态实现;

DUT
 

 

virtual class state;

   state_machine FSM;
   uvm_event_pool events_pool;
   uvm_event to_idle,to_state_a,to_state_b,to_state_c;

   function 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
   pure virtual task do_something();
   pure virtual task request_state_change();
endclass

class state_idle extends state;

   task do_something();
      $display("STATE_IDLE : nothing to do!
");
   endtask

   task request_state_change();
      state_t cur_state;
      fork: disable_fork
         begin
            to_state_a.wait_trigger();
            //$display("do something!
");
            cur_state = STATE_A;
         end
      join_any
      FSM.set_state(cur_state);
   endtask
endclass

class state_a extends state;

   task do_something();
      $display("STATE_A : do something!
");
   endtask

   task request_state_change();
      state_t cur_state;
      fork: disable_fork
         begin
            to_state_b.wait_trigger();
            //$display("do something!
");
            cur_state = STATE_B;
         end
         begin
            to_state_c.wait_trigger();
            //$display("do something!
");
            cur_state = STATE_C;
         end
      join_any
      disable fork;
      FSM.set_state(cur_state);
   endtask
endclass

class state_b extends state;

   task do_something();
      $display("STATE_B : do something!
");
   endtask

   task request_state_change();
      state_t cur_state;
      fork: disable_fork
         begin
            to_state_c.wait_trigger();
            //$display("do something!
");
            cur_state = STATE_C;
         end
         begin
            to_idle.wait_trigger();
            //$display("do something!
");
            cur_state = STATE_IDLE;
         end
      join_any
      disable fork;
      FSM.set_state(cur_state);
   endtask
endclass

class state_c extends state;

   task do_something();
      $display("STATE_C : do something!
");
   endtask

   task request_state_change();
      state_t cur_state;
      fork: disable_fork
         begin
            to_state_b.wait_trigger();
            //$display("do something!
");
            cur_state = STATE_B;
         end
         begin
            to_idle.wait_trigger();
            //$display("do something!
");
            cur_state = STATE_IDLE;
         end
      join_any
      disable fork;
      FSM.set_state(cur_state);
   endtask
endclass

class state_machine;

   local state state_m;
   state state_pool[state_t];

   function void set_state(state_t state);
      $display("Enter %s state!",state.name());
      state_m = state_pool[state];
   endfunction


   function void fsm_init();
      `REGISTER_STATE(IDLE,idle)
      `REGISTER_STATE(A,a)
      `REGISTER_STATE(B,b)
      `REGISTER_STATE(C,c)
      this.set_state(STATE_IDLE);
   endfunction

   task run();
      fsm_init();
      forever begin
         state_m.do_something();
         state_m.request_state_change();
      end
   endtask
endclass

 

note

state_machine中还可以加入reset stop函数控制FSM的更多行为;封装更多API供其他模块调用;加入assertion做基于cycle的条件判断;加入covergroup收集功能覆盖率;






审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分