当前位置:网站首页>Understand the Chisel language. 30. Chisel advanced communication state machine (2) - FSMD: Take Popcount as an example

Understand the Chisel language. 30. Chisel advanced communication state machine (2) - FSMD: Take Popcount as an example

2022-08-02 07:53:00 github-3rr0r

Chisel进阶之通信状态机(二)——FSMD:以Popcount为例

The previous article used flash as an example,The writing method of the communication state machine is introduced,It is used to decompose a large complex state machine into small multiple state machines that communicate with each other,Less resources can be guaranteed to be used,维护、Modifications are also easier.However, the communication between the communication state machines in the previous article is all control signals,Data signals are not yet involved.This article will learn about state machines with data paths,并以PopcountThe counter is introduced as an example.

State machine with data path

A typical example of a communication state machine is a state machine with a data path,Such state machines have special names,即FSMD(Finite-State Machine with Datapath,Finite state machine with data path).The state machine controls the data path,The datapath performs the computation.FSMDThere are inputs from the environment and inputs from the datapath,Where input from the environment is fed into the datapath,The datapath in turn generates data.下图就是一个典型的FSMD:

在这里插入图片描述

Popcount的例子

The example above is actually a calculationPopcount的FSMD,这个Popcount也叫Hamming Weight(汉明权重),Refers to a binary string1的数量.

PopcountCells contain data inputsdinand the resulting outputpopCount,Both are connected to the datapath.对于输入输出,我们使用ready-valid握手协议.When the sender data is valid,valid信号被设置,When the receiver can accept the data,ready信号被设置.when both signals are set,Data transfer happens.The handshake signal is connected toFSM上,FSMconnected to the data path,包括FSMControl signals to the datapath and datapath toFSM的状态信号.

Next we can design thisFSM了,Start with the state transition diagram first,That is, the example diagram given above.FSM从Idle状态开始,等待输入.when the data arrives,会给出一个valid信号,FSM会进入到Loadstate to read a shift register.然后FSM进入下一个状态Count,here in the binary string1will be counted sequentially.Here we use a shift register,一个加法器,an accumulator register,and a down counter to complete the count.When the down counter reaches zero,计算就完成了,FSM进入下一个状态Done,此时带valid信号的FSMThe signal is given,FSMThe signal contains what will be usedpopCount值.when received from the receiverready信号后,FSM就转移到Idle状态,准备计算下一个popCount.

The code below is a description of the top-level module,会对FSMand the data section is initialized,并将他们连接起来:

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)
    // fsmconnection to the top-level interface
    fsm.io.dinValid := io.dinValid
    io.dinReady := fsm.io.dinReady
    io.popCountValid := fsm.io.popCountValid
    fsm.io.popCountReady := io.popCountReady
    // The connection between the datapath and the top-level interface
    data.io.din := io.din
    io.popCount := data.io.popCount
    // 数据通路和fsm之间的连接
    data.io.load := fsm.io.load
    fsm.io.done := data.io.done
}

Comments simply state what the top-level module code means,这里就不多说了.Let's start by looking at the structure of the datapath,The following figure is a schematic diagram of the data path section:

在这里插入图片描述

数据din首先输入到shf寄存器中.在加载数据的时候,cnt寄存器置零.为了统计1的数量,regDataThe deposit will be shifted to the right(图片中的shf),The least significant bit is added every clock cycleregPopCount上(图片中的cnt).There is also a register map that is not drawn,It performs a countdown,until all bits in the input have been shifted out as least significant bits,计数器为0的时候就表明popCount计算结束了.此时FSM会切换到Done状态,在popCountReadyThe resulting signal is output when the signal is set.when the result is read,通过设置popCountValidSignal output data and letFSM切换回Idle状态.The following is the data path sectionChisel代码实现:

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信号有效时,regDataThe register is loaded with the input,regPopCountregisters will be reset to 0,计数寄存器regCountwill be set to the number of bits to be shifted.否则,regDataregister shift right,The least significant bits that were shifted out are added toregPopCount寄存器上,倒数计数器regCount自减一.当计数器为零时,regPopCountThe value of is to be calculatedpopCount.

PopCountFSM有三种状态,从idle开始.When the input data is valid signaldinValid被设置时,FSM会切换到count状态,and wait for the datapath to complete the computation,当popCount有效时,FSM切换到done状态,直到接收到popCntReadysignal and transmit the data,再切换为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)
}

The code in this part is similar to the previous state machine code,就不解释了.下面是测试代码:

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为例,Finite state machines with data paths are introducedFSMDwriting and implementation,It has a key guiding significance for writing complex systems later.我们可以注意到,在FSMD的实现中,Communication between state machines we useReady-Valid握手协议,This is a common communication interface protocol,But it's obviously a bit complicated to write this every time.而Chisel中自带了Ready-Valid相关的函数DecoupledIO,for data signalsReady-Valid协议的封装,In the next article we will learn about this important and convenient function.

原网站

版权声明
本文为[github-3rr0r]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/214/202208020645372195.html