当前位置:网站首页>吃透Chisel语言.30.Chisel进阶之通信状态机(二)——FSMD:以Popcount为例
吃透Chisel语言.30.Chisel进阶之通信状态机(二)——FSMD:以Popcount为例
2022-08-02 06:45:00 【github-3rr0r】
Chisel进阶之通信状态机(二)——FSMD:以Popcount为例
上一篇文章以闪光灯为例,介绍了通信状态机的写法,用于将大的复杂的状态机分解为小的多个相互通信的状态机来实现,可以保证使用资源更少,维护、修改也更容易。不过上一篇文章中的通信状态机之间的通信都是控制信号,还未涉及数据信号。这一篇文章就一起学习带数据通路的状态机,并以Popcount计数器为例进行介绍。
带数据通路的状态机
通信状态机的典型例子就是带数据通路的状态机,这种状态机有专门的名字,即FSMD(Finite-State Machine with Datapath,带数据通路的有限状态机)。其中状态机控制数据通路,数据通路执行计算。FSMD的输入有来自环境的输入和来自数据通路的输入,其中来自环境的输入会输入到数据通路,数据通路又生成数据。下图就是一个典型的FSMD:

Popcount的例子
上图的例子其实就是个计算Popcount的FSMD,这个Popcount也叫Hamming Weight(汉明权重),指的是一个二进制串中1的数量。
Popcount单元包含数据输入din和结果输出popCount,两个都连接到数据通路。对于输入输出,我们使用ready-valid握手协议。当发送端数据有效的时候,valid信号被设置,当接受端可以接受数据的时候,ready信号被设置。当两个信号都被设置的时候,数据传输就会发生。握手信号连接到FSM上,FSM连接到数据通路上,包括FSM到数据通路的控制信号和数据通路到FSM的状态信号。
下一步我们就可以设计这个FSM了,首先从状态转换图开始,也就是上面给出的例子图。FSM从Idle状态开始,等待输入。当数据到达的时候,会给出一个valid信号,FSM会进入到Load状态来读取一个移位寄存器。然后FSM进入下一个状态Count,这里二进制串中的1会被顺序计数。这里我们使用一个移位寄存器,一个加法器,一个累加器寄存器,以及一个向下计数器来完成计数。当向下计数器到零的时候,计算就完成了,FSM进入下一个状态Done,此时带valid信号的FSM信号就给出了,FSM信号中包含了将要被使用的popCount值。当收到了接收端的ready信号后,FSM就转移到Idle状态,准备计算下一个popCount。
下面的代码是顶层模块的描述,会对FSM和数据部分进行初始化,并将他们连接起来:
class PopCount extends Module {
val io = IO(new Bundle {
// 输入数据有效
val dinValid = Input(Bool())
// 可以接收数据
val dinReady = Output(Bool())
// 输入数据
val din = Input(UInt(8.W))
// 输出结果有效
val popCountValid = Output(Bool())
// 可以输出数据
val popCountReady = Input(Bool())
// 输出结果
val popCount = Output(UInt(4.W))
})
// fsm部分
val fsm = Module(new PopCountFSM)
// 数据通路部分
val data = Module(new PopCountDataPath)
// fsm和顶层接口的连接
fsm.io.dinValid := io.dinValid
io.dinReady := fsm.io.dinReady
io.popCountValid := fsm.io.popCountValid
fsm.io.popCountReady := io.popCountReady
// 数据通路和顶层接口的连接
data.io.din := io.din
io.popCount := data.io.popCount
// 数据通路和fsm之间的连接
data.io.load := fsm.io.load
fsm.io.done := data.io.done
}
注释简单地说明了顶层模块代码的含义,这里就不多说了。下面开始看数据通路的构造,下图是数据通路部分的示意图:

数据din首先输入到shf寄存器中。在加载数据的时候,cnt寄存器置零。为了统计1的数量,regData寄存会右移(图片中的shf),最低有效位在每个时钟周期都加到regPopCount上(图片中的cnt)。还有个寄存器图中没有画出来,它执行倒数计数,直到输入中所有的位都以最低有效位的形式移出,计数器为0的时候就表明popCount计算结束了。此时FSM会切换到Done状态,在popCountReady信号被设置时输出结果信号。当结果被读取时,通过设置popCountValid信号输出数据并让FSM切换回Idle状态。下面是数据通路部分的Chisel代码实现:
class PopCountDataPath extends Module {
val io = IO(new Bundle {
val din = Input(UInt(8.W))
val load = Input(Bool())
val popCount = Output(UInt(4.W))
val done = Output(Bool())
})
val dataReg = RegInit(0.U(8.W))
val popCountReg = RegInit(0.U(4.W))
val counterReg = RegInit(0.U(4.W))
dataReg := 0.U ## dataReg(7, 1)
popCountReg := popCountReg + dataReg(0)
val done = counterReg === 0.U
when (!done) {
counterReg := counterReg - 1.U
}
when (io.load) {
dataReg := io.din
popCountReg := 0.U
counterReg := 8.U
}
// 调试用
printf("%b %d\t", dataReg, popCountReg)
io.popCount := popCountReg
io.done := done
}
在load信号有效时,regData寄存器会加载输入,regPopCount寄存器会复位到0,计数寄存器regCount会设置为需要被移位的位数。否则,regData寄存右移,被移出的最低有效位会加到regPopCount寄存器上,倒数计数器regCount自减一。当计数器为零时,regPopCount的值就是要计算的popCount。
而PopCountFSM有三种状态,从idle开始。当输入数据有效信号dinValid被设置时,FSM会切换到count状态,并等待数据通路完成计算,当popCount有效时,FSM切换到done状态,直到接收到popCntReady信号并传送完数据,再切换为idle状态,等待下一轮计算。FSM部分的Chisel实现如下:
class PopCountFSM extends Module {
val io = IO(new Bundle {
val dinValid = Input(Bool())
val dinReady = Output(Bool())
val popCountValid = Output(Bool())
val popCountReady = Input(Bool())
val load = Output(Bool())
val done = Input(Bool())
})
val idle :: count :: done :: Nil = Enum(3)
val stateReg = RegInit(idle)
io.load := false.B
io.dinReady := false.B
io.popCountValid := false.B
switch(stateReg) {
is(idle) {
io.dinReady := true.B
when(io.dinValid) {
io.load := true.B
stateReg := count
}
}
is(count) {
when(io.done) {
stateReg := done
}
}
is(done) {
io.popCountValid := true.B
when(io.popCountReady) {
stateReg := idle
}
}
}
// 调试用
printf("state: %b\n", stateReg)
}
这一部分的代码和之前状态机的代码类似,就不解释了。下面是测试代码:
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
class SimpleTestExpect extends AnyFlatSpec with ChiselScalatestTester {
"DUT" should "pass" in {
test(new PopCount) {
dut =>
dut.clock.step()
dut.io.din.poke("b10010011".U)
dut.io.dinValid.poke(true.B)
for (a <- 0 until 12) {
dut.clock.step()
}
dut.io.popCountReady.poke(true.B)
dut.clock.step()
dut.clock.step()
dut.clock.step()
dut.clock.step()
}
}
}
输出如下:
0 0 state: 0
0 0 state: 0
10010011 0 state: 1
1001001 1 state: 1
100100 2 state: 1
10010 2 state: 1
1001 2 state: 1
100 3 state: 1
10 3 state: 1
1 3 state: 1
0 4 state: 1
0 4 state: 10
0 4 state: 10
0 4 state: 10
0 4 state: 0
10010011 0 state: 1
1001001 1 state: 1
测试通过。
结语
这一篇文章以Popcount为例,介绍了带数据通路的有限状态机FSMD的写法与实现,对于后面写复杂的系统有很关键的指导意义。我们可以注意到,在FSMD的实现中,状态机之间的通信我们使用了Ready-Valid握手协议,这是一种常见的通信接口协议,但每次都这么写显然有点复杂。而Chisel中自带了Ready-Valid相关的函数DecoupledIO,用于对数据信号进行Ready-Valid协议的封装,下一篇文章我们就来学习这个重要又方便的函数。
边栏推荐
- Vscode connect to remote server "Acquiring the lock on the/home / ~ 'problem
- (Part of it is not understood, and the notes are not completed) [Graph Theory] Difference Constraints
- Summer Summary (3)
- Wuhan 2022 organizing of the high-performance computing added new ecological development of high-performance computing
- Day 4 of HCIP
- 倍福使用AdsRemote组件实现和C#的ADS通讯
- 【机器学习】实验5布置:AAAI会议论文聚类分析
- 2022夏暑假每日一题(六)
- CSRF-跨站请求伪造-相关知识
- 数据库概论之MySQL表的增删改查2
猜你喜欢

Clapper that can interact with the audience in real time

享年94岁,图灵奖得主、计算复杂性理论先驱Juris Hartmanis逝世

张驰课堂:六西格玛测量系统的误差分析与判定
![[npm install error report collection] - npm ERR! code ENOTEMPTY npm ERR! syscall rmdir](/img/c5/2c42e26e577506573985b30669ca6c.png)
[npm install error report collection] - npm ERR! code ENOTEMPTY npm ERR! syscall rmdir

chrome plugin development guide

Specified URL is not reachable,caused by :‘Read timed out

Revitalize rural circular economy and digital chain to link agricultural "ecological chain"

Gradle系列——Gradle插件(基于Gradle文档7.5)day3-2

“蔚来杯“2022牛客暑期多校训练营4,签到题NDKHL

堡垒机、堡垒机的原理
随机推荐
【暑期每日一题】洛谷 P1551 亲戚
optional
反射课后习题及做题记录
【故障诊断分析】基于matlab FFT轴承故障诊断【含Matlab源码 2001期】
About the local server problem after ue4.27 pixel streaming package
速看!PMP新考纲、PMBOK第七版解读
论文《Deep Multifaceted Transformers for Multi-objective Ranking in Large-Scale E-commerce Recommender》
FaceBook社媒营销高效转化技巧分享
Connection reset by peer problem analysis
.NET Static Code Weaving - Rougamo Release 1.1.0
Facebook社媒营销的5大技巧,迅速提高独立站转化率!
Redis 常用命令和基本数据结构(数据类型)
SimpleChannelInboundHandler使用总结
Servlet
Submit code process
张驰咨询:企业实施精益管理的最大障碍,只把精益作为一种工具和方法
实例026:递归求阶乘
你认同这个观点吗?大多数企业的数字化都只是为了缓解焦虑
【故障诊断分析】基于matlab FFT轴承故障诊断(包络谱)【含Matlab源码 2002期】
[21天学习挑战赛——内核笔记](一)——设备树的概述(硬件、目标、效果、文件类型)