Some question about fsm dialect?

I’m learning the circt project, I started with calyx dialect code and after a series of passes the code looks like this.After thinking about it for a long time, I still can’t understand the design idea of fsm dialect.I don’t know how to understand the fsm dialect, which I think is similar to Moore’s state machine, but different from Moore.
The following code can be used as a reference, I have the following questions.

  • Why is there a return value in the state machine? What is the purpose of this return value?
    fsm.return %arg1, although it is used in calyx.wires, I still can’t figure out what it does.
  • What is the use of %save_done.in, %save_done.out ?
    I have read the material here.But I still didn’t understand it very well.

If anyone can help me, I would be grateful.Thank you!

module {
  fsm.machine @control(%arg0: i1, %arg1: i1) -> (i1, i1) attributes {calyx.fsm_group_done_inputs = {save = 0 : i64}, calyx.fsm_group_go_outputs = {save = 0 : i64}, calyx.fsm_top_level_done = 1 : i64, calyx.fsm_top_level_go = 1 : i64, compiledGroups = [@save], initialState = "fsm_entry"} {
    %true = hw.constant true
    %false = hw.constant false
    fsm.state @fsm_entry output {
      fsm.output %false, %false : i1, i1
    } transitions {
      fsm.transition @seq_0_save guard {
        fsm.return %arg1
      }
    }
    fsm.state @fsm_exit output {
      fsm.output %false, %true : i1, i1
    } transitions {
    }
    fsm.state @seq_0_save output {
      fsm.output %true, %false : i1, i1
    } transitions {
      fsm.transition @fsm_exit guard {
        fsm.return %arg0
      }
    }
  }
  calyx.component @identity(%in: i32, %go: i1 {go}, %clk: i1 {clk}, %reset: i1 {reset}) -> (%out: i32, %done: i1 {done}) {
    %save_done.in, %save_done.out = calyx.std_wire @save_done : i1, i1
    %0:2 = fsm.hw_instance "controller" @control(%save_done.out, %go), clock %clk, reset %reset : (i1, i1) -> (i1, i1)
    %r.in, %r.write_en, %r.clk, %r.reset, %r.out, %r.done = calyx.register @r : i32, i1, i1, i1, i32, i1
    %true = hw.constant true
    %true_0 = hw.constant true
    calyx.wires {
      calyx.assign %out = %r.out : i32
      calyx.assign %done = %0#1 : i1
      calyx.assign %save_done.in = %r.done : i1
      calyx.assign %r.in = %0#0 ? %in : i32
      calyx.assign %r.write_en = %0#0 ? %true : i1
    }
    calyx.control {
    }
  }
}

I found slides about the FSM dialect in the CIRCT Weekly Discussion.


I think this picture is a good way to express my doubts.
Why is there an [in] between the IDLE state and the RUN state?I know the input should change the state of the state machine. Here [in] is the input?From the picture it seems that the input to the RUN state is cnt. But it appears that cnt!=0 and cnt==0, it doesn’t seem to be reflected in the code, which is really hard to understand.

I have never actually used the FSM dialect, but here is my understanding, maybe that can help you.

An fsm.state specifies as you probably guessed a state of the state machine. It can have a few regions attached to it:

  • the output region specifies what the output of the entire state machine should be when the FSM is in the given state. The fsm.output operation passes that information to the FSM.
  • the transitions region specifies to which states the FSM can go starting from the given state. Each transition specifies a possible target state. To specify whether a transition can be taken, the transition can be attached a guard region that returns a boolean (using fsm.return) specifying whether in this state the transition can be taken. The FSM will then pick the first transition in the order of the list that has a guard returning true at its point in time.

In your example, the control FSM has three states: fsm_entry, fsm_exit and seq_0_save.

  • From fsm_entry, you can transition to seq_0_save if and only if %arg1 is set to 1. If that is not the case, nothing will happen and the FSM will stay in fsm_entry until the next clock cycle where this will be checked again. When the FSM is in this state, the machine itself outputs (false, false).
  • In fsm_exit, there is no transition out because it is a final state. In this state, the FSM outputs (false, true).
  • In seq_0_save, the FSM can transition to fsm_exit is and only if %arg0 is true. In this state, the FSM will output (true, false).

I hope this helps! Have you seen the FSM rationale document, by the way? It explains everything in more details.

1 Like

Thank you really :smiley:, I didn’t read the documentation there because I didn’t know there was documentation to read.

1 Like