https://www.chisel-lang.org/docs/cookbooks/cookbook#how-do-i-create-a-finite-state-machine-fsm
chisel手册,状态机中的理解
代码
import chisel3._
import chisel3.util.{switch, is}
object DetectTwoOnes {
object State extends ChiselEnum {
val sNone, sOne1, sTwo1s = Value
}
}
/* This FSM detects two 1's one after the other */
class DetectTwoOnes extends Module {
import DetectTwoOnes.State
import DetectTwoOnes.State._
val io = IO(new Bundle {
val in = Input(Bool())
val out = Output(Bool())
val state = Output(State())
})
val state = RegInit(sNone)
io.out := (state === sTwo1s)
io.state := state
switch (state) {
is (sNone) {
when (io.in) {
state := sOne1
}
}
is (sOne1) {
when (io.in) {
state := sTwo1s
} .otherwise {
state := sNone
}
}
is (sTwo1s) {
when (!io.in) {
state := sNone
}
}
}
}
代码理解:
这段代码是用Chisel硬件设计语言实现的一个简单的有限状态机(FSM),用于检测连续两个逻辑“1”。以下是对代码的详细中文解释:
导入模块和工具
import chisel3._
: 导入Chisel库,这是使用Chisel进行硬件设计的基础。import chisel3.util.{switch, is}
: 导入Chisel的switch
和is
工具,这些工具用于构建条件分支,类似于其他编程语言中的switch-case
语句。
定义状态机的状态
- 在
DetectTwoOnes
对象中定义一个名为State
的枚举类型,用于表示状态机的状态。这里定义了三个状态:sNone
:初始状态,表示到目前为止没有检测到“1”。sOne1
:第一状态,表示已经检测到一个“1”。sTwo1s
:第二状态,表示连续检测到两个“1”。
状态机的实现
class DetectTwoOnes
是一个Chisel模块,实现了上述定义的状态机。- 定义了一个名为
io
的接口,包括:in
:输入信号,类型为Bool()
,表示接收外部的逻辑信号。out
:输出信号,类型为Bool()
,当状态机处于sTwo1s
状态时输出为true
,表示已经检测到两个连续的“1”。state
:输出当前状态机的状态,用于调试或测试。
状态机逻辑
- 使用
switch
语句来根据当前的状态执行不同的操作:is(sNone)
: 当状态为sNone
时,如果输入为true
(即检测到“1”),则状态转移到sOne1
。is(sOne1)
: 当状态为sOne1
时,如果再次输入为true
,则状态转移到sTwo1s
,表示连续检测到两个“1”。如果输入为false
,则返回到sNone
状态。is(sTwo1s)
: 当状态为sTwo1s
时,如果输入为false
,则状态返回到sNone
,等待下一次连续两个“1”的检测。
功能描述
- 该状态机启动时在
sNone
状态,等待输入信号。 - 当检测到一个“1”后,进入
sOne1
状态。 - 如果在
sOne1
状态下再次检测到“1”,则进入sTwo1s
状态,并通过out
输出信号表示检测到连续两个“1”。 - 如果在任何状态下检测到“0”,状态机将重置回
sNone
状态。
这种类型的状态机在数字电路设计中常用于序列检测,如网络数据流中特定模式的检测等。
细节理解:
import的部分理解
import DetectTwoOnes.State
import DetectTwoOnes.State._
在的代码中,使用了两个import
语句来引入DetectTwoOnes.State
,这些语句的作用和含义如下:
1. import DetectTwoOnes.State
这条语句导入了DetectTwoOnes
对象中定义的State
枚举类型。通过这种导入,您可以在当前作用域中直接使用State
来引用这个枚举类型,而不需要每次都使用完整的路径DetectTwoOnes.State
。这样做的好处是简化了代码的书写,提高了代码的可读性。
2. import DetectTwoOnes.State._
这条语句进一步导入了DetectTwoOnes.State
枚举中定义的所有值(成员),如sNone
、sOne1
和sTwo1s
。这意味着您可以直接在代码中使用这些枚举值,而无需每次都加前缀State.
。
实际应用
这样的导入方式使得在定义和操作状态机时代码更为简洁明了。例如,当您需要检查或设置状态机的状态时,可以直接写:
state := sNone
而不是:
state := DetectTwoOnes.State.sNone
这两条import
语句共同使得代码更为简洁,提高了开发效率,同时保持了代码的易读性。在复杂的项目中,适当地使用这种导入策略可以大大减少代码的冗余,并且使得来自同一模块或包的不同部分更加紧密地协作。
状态相关
io.out := (state === sTwo1s)
io.state := state
在代码片段中,io.out
和io.state
是两个与输入/输出相关的接口定义,它们是状态机DetectTwoOnes
的关键部分,用于与外部系统交互。这些行如何工作及其意义如下:
1. io.out := (state === sTwo1s)
这行代码设置了输出信号io.out
的值。具体来说,io.out
是一个布尔类型的输出(Bool()
),该输出依赖于状态机的当前状态是否为sTwo1s
。
- 表达式解释:
(state === sTwo1s)
是一个条件表达式,检查当前的状态(由寄存器state
保存)是否等于sTwo1s
状态。这里使用的===
是Chisel中的相等比较运算符,用于比较两个数据元素是否相等。 - 行为:如果状态机当前处于
sTwo1s
状态,表明已经连续检测到两个逻辑“1”,这时表达式(state === sTwo1s)
的结果为true
,因此io.out
将输出true
。如果不是sTwo1s
状态,io.out
输出false
。
这种设计使得外部系统可以通过检查io.out
的值来知道是否检测到了连续的两个“1”。
2. io.state := state
这行代码将内部状态寄存器state
的当前值直接输出到io.state
。io.state
是一个枚举类型的输出,与内部的state
寄存器类型相同。
- 功能:通过将内部状态直接输出,可以方便地进行调试或监控状态机的行为。外部系统或测试设备可以读取这个值,了解状态机在任意时刻的状态。
- 用途:在实际应用中,这可以用于系统的状态监测、故障诊断或者系统行为的验证。
这两行代码共同定义了状态机与外部世界的接口行为,一方面通过io.out
提供业务逻辑所需的信号输出,另一方面通过io.state
提供系统状态信息,以便进行监控和调试。这样的设计不仅增强了模块的功能完整性,也便于模块的集成和测试。