Learning BSV‎ > ‎Advanced Bluespec‎ > ‎

Synchronous State Machine

With Bluespec, a state machine can be written by a series of independent rules, which the compiler will properly order and synthesize control logic. Alternately, the transitions can be combined into a function and that function instantiated in one rule, which highlights the independent and synchronous nature of the rules.

FSM with Multiple Rules

...
typedef enum S0, S1, S2, S3 StateType
deriving (Eq, Bits);
...
Reg#(StateType) curr_state <- mkReg (S0) ;

(* fire_when_enabled, no_implicit_conditions *)
rule state_S0 (curr_state == S0);
curr_state <= S1;
endrule

(* fire_when_enabled, no_implicit_conditions *)
rule state_S1 (curr_state == S1);
curr_state <= S2;
endrule

(* fire_when_enabled, no_implicit_conditions *)
rule state_S2 (curr_state == S2);
curr_state <= S3;
endrule

(* fire_when_enabled, no_implicit_conditions *)
rule state_S3 (curr_state == S3);
curr_state <= S0;
endrule
...

Each rule corresponds to one or more state transitions, where the rule condition is the current state and input condition for transition to occur.

Each rule is also annotated with a fire_when_enabled attribute. This attribute enables compile time checks to insure that other conditions (rules or method will not block the rule execution -- basically a check for independence between rules.)

The no_implicit_condition attribute, is a compile-time assertion which insures that there are no implicit conditions (such as full or empty FIFOs) which would prevent this rule from firing. Together, these attribute check the designer's intentions and understanding of the Bluespec model.

FSM with One Rule

Alternately, the FSM may be described in one rule, which gives the full FSM behavior in a case statement.

 Reg#(StateType) curr_state <-  mkReg (S0) ;

(* fire_when_enabled *)
rule rule1_StateChange (True);
StateType next_state;
case (curr_state)
S0 : next_state = S1;
S1 : next_state = S2;
S2 : next_state = S3;
S3 : next_state = S0;
default : next_state = S0;
endcase
curr_state <= next_state;
endrule: rule1_StateChange

Another One Rule FSM Example

This FSM example is a minor variation of the above, where a function describes the state transitions and the rule instantiates the function. This style has the advantage that the rule bodies, which update state, and call actions are separate from the function, thus allowing easier maintenance and reuse.

typedef enum S0, S1, S2, S3 StateType
deriving (Eq, Bits);
function StateType next_state (StateType curr_state);
let myLocalVar;
case (curr_state)
S0 : myLocalVar = S1;
S1 : myLocalVar = S2;
S2 : myLocalVar = S3;
S3 : myLocalVar = S0;
default : myLocalVar = S0;
endcase
return myLocalVar;
endfunction

...

rule rule1_StateChange (True);
curr_state <= next_state(curr_state);
endrule: rule1_StateChange

Discussion

The implementation style for an FSM strongly depends on scope of the FSM within the design, where the following guidelines should be used:

  • If the FSM implements only the control structure, that is, it provides the next state logic, but does not detail the actions which occur within a given state, then the FSM should be implemented in one rule. This is similar to common Verilog styles, and does not take advantage of Bluespec features.
  • If the FSM design includes the actions within each state, then the recommended style is one rule per transition or state arc. That is, given two transition, state A to B and state A to C, there should be a two rules, one per transition. This style has the advantage that Bluespec can automatically handle implicit conditions of the actions, thus shortening design, implementation and verification time. For example, if some actions in the transition from A to B are not ready, then the rule does not fire, and the state transition will not occur. Bluespec collects and analyzes these action implicit condition and then builds logic for correct behavior.

The use of multiple rules per FSM is also recommended for multiple interacting FSMs, since each rule describes correct behavior allowing Bluespec to analyze and build the correct concurrent operations of the machines.


Comments