凿子标准库移位寄存器的行为对于启用线是不是正确

Posted

技术标签:

【中文标题】凿子标准库移位寄存器的行为对于启用线是不是正确【英文标题】:Is the behavior of the chisel standard library shift register correct for the enable line凿子标准库移位寄存器的行为对于启用线是否正确 【发布时间】:2014-10-06 23:30:10 【问题描述】:

我正在尝试创建一个涉及移位寄存器的数据路径,但我希望整个过程能够在等待新输入时停止。我看到标准库中有一个带启用线的移位寄存器(虽然默认为 true)。

问题是当我尝试使用它时,编译的verilog似乎并没有在启用低时真正停止移位寄存器。

考虑一下这个凿码:

package SR

import Chisel._

class SR extends Module 
  val io = new Bundle  
    val in = UInt(INPUT, 8)
    val enable = Bool(INPUT)
    val out = UInt(OUTPUT, 8)
  
  io.out:= ShiftRegister(io.in, 10, io.enable)


class SRTests(c: SR) extends Tester(c) 


object SR 
  def main(args: Array[String]): Unit = 
    val tutArgs = args.slice(1, args.length)
    chiselMainTest(tutArgs, () => Module(new SR())) 
      c => new SRTests(c) 
  

我得到以下verilog:

module SR(input clk,
    input [7:0] io_in,
    input  io_enable,
    output[7:0] io_out
);

  reg [7:0] R0;
  reg [7:0] R1;
  reg [7:0] R2;
  reg [7:0] R3;
  reg [7:0] R4;
  reg [7:0] R5;
  reg [7:0] R6;
  reg [7:0] R7;
  reg [7:0] R8;
  reg [7:0] R9;
  wire[7:0] T10;

`ifndef SYNTHESIS
  integer initvar;
  initial begin
    #0.002;
    R0 = 1$random;
    R1 = 1$random;
    R2 = 1$random;
    R3 = 1$random;
    R4 = 1$random;
    R5 = 1$random;
    R6 = 1$random;
    R7 = 1$random;
    R8 = 1$random;
    R9 = 1$random;
  end
`endif

  assign io_out = R0;
  assign T10 = io_enable ? io_in : R9;

  always @(posedge clk) begin
    R0 <= R1;
    R1 <= R2;
    R2 <= R3;
    R3 <= R4;
    R4 <= R5;
    R5 <= R6;
    R6 <= R7;
    R7 <= R8;
    R8 <= R9;
    if(io_enable) begin
      R9 <= io_in;
    end
  end
endmodule

似乎移位寄存器只保持第一个值固定而不是整个值。例如,如果您在连续时钟周期中写入 1、2、3、4、5,但只为 1、2、3 保持启用高电平,则 3 将正确保持,但 1 和 2 最终会移出,整个移位寄存器将填充值 3。

我想要类似于凿子教程中的移位寄存器示例的行为。问题是我需要长的、可参数化的移位寄存器,所以手写每个寄存器不是一种选择。我将非常感谢凿子代码的示例,该代码实现了具有启用行为的移位寄存器,如凿子教程中所见,但参数化为不同长度,如标准库中所见。

【问题讨论】:

【参考方案1】:

您可以在Chisel 存储库中的 src/main/scala/ChiselUtil.scala 中查看 ShiftRegister 的源代码:

object ShiftRegister

  def apply[T <: Data](in: T, n: Int, en: Bool = Bool(true)): T =
  
    // The order of tests reflects the expected use cases.
    if (n == 1) 
      RegEnable(in, en)
     else if (n != 0) 
      RegNext(apply(in, n-1, en))
     else 
      in
    
  

这是创建 RegNext 的递归链,但基本情况是创建 RegEnable。示例:

RegNext(RegNext(RegNext(RegEnable(in, en))))

您可以将该代码复制到您的 hello world 中,将其重命名为 object MyShiftRegister,然后修改该循环以满足您的需要。

我认为您正在寻找的是:

 else if (n != 0) 
  RegEnable(apply(in, n-1, en), en)
 ...

作为一般策略,我建议写出代码“展开”后的样子,然后考虑如何将其“打包”成一段简洁且可参数化的 Scala 代码。

【讨论】:

好的,谢谢,我会试试这个。这个实现的目的是什么:RegNext(RegNext(RegNext(RegEnable(in, en))))?此外,移位寄存器代码最近是否更改为具有 if else 和 else 情况?我以为上次看它时,它只有 if 和 else(现在是 else if)。这是否只是说如果 n 作为移位寄存器的参数没有意义,则作为输出传入。 我没有写 Chisel,所以我不知道他们对它做了什么改变,也不知道他们为什么做出这些改变。 Chisel google-group 可能是解决“设计意图”等问题的更好论坛。

以上是关于凿子标准库移位寄存器的行为对于启用线是不是正确的主要内容,如果未能解决你的问题,请参考以下文章

Atmega32 移位 PORTA 不会循环遍历整个寄存器

集成芯片74LS164的移位原理是啥?

什么是PRBS

CCD移位寄存器 的工作原理是啥啊

数字电路实验 06 - | 移位寄存器及其应用

C++移位运算符