首页 > 解决方案 > Chisel3 每个时钟周期比较 UInt 位 [运行长度编码器]

问题描述

我正在构建一个运行长度编码器模块,但遇到了问题。

原始比特流作为 uint8 存储在内存中:11111100 -> 252、00000110 -> 6 等

我将原始比特流的每个块加载到一个寄存器中val in = Reg(UInt(8.W)),然后我想将第 1 位与第 2 位进行比较,然后将第 2 位与第 3 位进行比较,依此类推,以计算运行的长度。这是我的状态机的一部分。

switch(state) {
  // code here ...
  is(step1) {
    logic.io.current_bit := in(7)
    logic.io.next_bit := in(6)
    // code here ...
  }
  is(step2) {
    current_bit := in(6)
    next_bit := in(5)
    // code here ...
  }
  // ... more steps ...
  is(step7) {
    current_bit := in(1)
    next_bit := in(0)
    // code here ...
  }
  // code here ...
}

我有一个名为逻辑的组合电路,它决定两个连续位的相等性,以及下一个状态是步骤 n+1 还是存储运行的长度。我认为有很多代码冗余,但我想不出另一种方式。

有没有办法输入 in(x) ,其中 x 是我的状态机中定义的数字?

关于如何以更优雅的方式做到这一点的任何想法?


编辑:

模块输入/输出:

val io = IO(new Bundle {
    val valid = Input(Bool()) // enables-disables the module
    val mem_addr_load = Input(UInt(mem_addr_length.W)) // memory position to load the uints
    val mem_addr_store = Input(UInt(mem_addr_length.W)) // memory position to store the uints
    val mem_in = Input(UInt(8.W)) // uint input - loads 252 so it translates 11111100 bitstream
    val mem_out = Output(UInt(8.W)) // store the run's length using 8-bit runs (up to 255 consecutive same bits)
    val mem_addr = Output(UInt(mem_addr_length.W)) // memory position that the module wants to access (store/load)
    val writeEn = Output(Bool()) // signifies that there are data to be written in the memory
    val ready = Output(Bool()) // signifies that the process is over
  })

模块功能:压缩内存内容

Memory contents (IN)
|11101111|11111111|11111111|11111111|10111110|00000000|00111111|11111111|11111111|11111111|11111111|11111111|11111111|11111100|

Memory contents (OUT)
|00000011|00000001|00011101|00000001|00000101|00001011|00111000|00000010|
|   4x1  |   1x0  |  29x1  |   1x0  |   5x1  |  11x0  |  56x1  |   2x0  | 

标签: chisel

解决方案


有没有办法输入 in(x) ,其中 x 是我的状态机中定义的数字?

您可以在设计中使用寄存器/线路进行位提取。例如,is状态机中的每个:

  is(step7) {
    current_bit := in(1)
    next_bit := in(0)
    // code here ...
  }

可以折叠成类似的东西

current_bit := in(state)
next_bit := in(state - 1.U)

(以整理一些细节为准)

我会考虑的另一件事是使用更多的聚合。我并不完全理解内存接口,但可以将其表示为:

val io = IO(new Bundle {
  val mem = new Bundle {
    val addr = Output(UInt(mem_addr_length.W))
    val dataIn = Input(UInt(8.W))
    val dataOut = Output(UInt(8.W))
    val writeEn = Output(Bool())
  }
})

使用某种形式的解耦(即现成有效)设计通常也更容易。例如,在这种情况下,我可能会有一个外部模块来与内存接口(如您编辑中的模块 I/O),以及一个内部模块来进行编码。例如。

val io = IO(new Bundle {
  val in = Decoupled(UInt(8.W)) // note Decoupled is defined in chisel3.util._
  val out = Decoupled(UInt(8.W))
})

经常解耦有助于减少问题规模

根据您的资源与延迟限制,您还可以考虑在每个周期对输入的多个位进行编码。这就是在编写生成器时可以提供一个有趣问题的东西。

人们可以认为这种编码本质上是一个可以实现为 ROM 的真值表。您可以通过几个维度对其进行参数化,包括每个周期编码的最大位数以及每个周期的最大编码运行数(尽管我怀疑对于每个周期单个字节的内存接口,没有理由让它大于1)。


推荐阅读