一、代码设计
- chisel代码
import chisel3._
import chisel3.util._
import chisel3.stage._
class EdgeDetect(resetValue: Option[UInt] = None) extends Module {
val io = IO(new Bundle {
val in = Input(UInt(1.W))
val pos = Output(UInt(1.W))
val neg = Output(UInt(1.W))
})
val reg = if (resetValue.isDefined) { // resetValue = Some(number)
RegInit(resetValue.get)
} else { //resetValue = None
Reg(UInt())
}
reg := io.in
when((reg===0.U)&&(io.in===1.U)){
io.pos := 1.U
io.neg := 0.U
}.elsewhen((reg===1.U)&&(io.in===0.U)){
io.pos := 0.U
io.neg := 1.U
}.otherwise {
io.pos := 0.U
io.neg := 0.U
}
}
// Generate the Verilog code
object EdgeDetectMain extends App {
println("Generating the EdgeDetect hardware")
(new chisel3.stage.ChiselStage).execute(Array("--target-dir", "generated"),
Seq(ChiselGeneratorAnnotation(() => new EdgeDetect(Some(1.U)))))
}
- 生成的verilog代码主体部分
module EdgeDetect(
input clock,
input reset,
input io_in,
output io_pos,
output io_neg
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
`endif // RANDOMIZE_REG_INIT
reg reg_; // @[EdgeDetect.scala 14:16]
wire _T_5 = reg_ & ~io_in; // @[EdgeDetect.scala 24:27]
assign io_pos = ~reg_ & io_in; // @[EdgeDetect.scala 21:21]
assign io_neg = ~reg_ & io_in ? 1'h0 : _T_5; // @[EdgeDetect.scala 21:37 EdgeDetect.scala 23:16]
always @(posedge clock) begin
reg_ <= reset | io_in; // @[EdgeDetect.scala 14:16 EdgeDetect.scala 14:16 EdgeDetect.scala 19:9]
end
endmodule
二、代码分析
reg := io.in
when((reg===0.U)&&(io.in===1.U)){
io.pos := 1.U
io.neg := 0.U
}.elsewhen((reg===1.U)&&(io.in===0.U)){
io.pos := 0.U
io.neg := 1.U
}.otherwise {
io.pos := 0.U
io.neg := 0.U
}
整个代码的核心部分就是上面这段,我们之所以可以通过这种形式获得信号的边沿信息,是因为Reg的延迟特性,也即只要你将一个信号赋值给Reg,那么此时你就可以理解为你获得了延迟一个clk后的该信号。
同时拥有了当前clk(端口io.in)
和延迟一个clk(定义的reg
)的信号之后,就和我们在verilog中进行边沿检测的方式完全一样了。从生成的verilog代码中也可以验证这一点。具体可以参考我的另一篇文章:
还有一点需要注意的是:
例如我们在测试时,执行了
io.in.poke(1.U)
,此时如果你不执行step(1)
,从代码的角度看,可以理解为此时的reg并没有被赋值,或者说还没被更新,也即reg != 1.U
。chisel虽然是高级语言的写法,但是我们必须时刻记得这是在设计硬件电路。
因此,
step(1)
写在expect()
前面和后面两种情况下,有时候就会产生不一样的结果。如果不想出错,一点要谨记上面所说的点:
- 如果写在了
expect()
前面,此时poke的新数据已经更新给了reg,那么就可以根据新数据计算实际结果,然后和模型输出作比较;- 如果写在了
expect()
后面,那么poke的新数据还未更新给reg,就不能使用新数据计算实际结果,否则和模型输出进行比较的时候,两者是不一致的,就会报错。
不过具体情况还需具体分析,只需要注意reg的延迟特性即可!!!