2. LED流水灯
任务目标
设计一个基于Chisel的循环移位寄存器,驱动8个LED实现流水灯效果。核心目标是掌握时序逻辑(寄存器)的基本写法,理解同步复位与寄存器更新逻辑。
环境依赖
需要安装sbt和Chisel(本案例使用Chisel 3.6.0,Scala 2.13.10)。在项目build.sbt中声明:
scalaVersion := "2.13.10"
libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.6.0"
addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % "3.6.0" cross CrossVersion.full)
实现代码
完整代码如下,保存为LedShifter.scala:
import chisel3._
import chisel3.util._
class LedShifter extends Module {
val io = IO(new Bundle {
val led = Output(UInt(8.W))
})
// 同步复位,初始值为0x01(最右侧LED点亮)
val shiftReg = RegInit(0x01.U(8.W))
// 每个时钟周期左移一位,最低位补移位前的最高位(循环移位)
shiftReg := Cat(shiftReg(6, 0), shiftReg(7))
io.led := shiftReg
}
// 生成Verilog
object LedShifterMain extends App {
(new chisel3.stage.ChiselStage).emitVerilog(new LedShifter)
}
运行方式
在项目根目录执行以下命令生成Verilog:
sbt "runMain LedShifterMain"
生成的文件为LedShifter.v,其核心内容为:
module LedShifter(
input clock,
input reset,
output [7:0] io_led
);
reg [7:0] shiftReg;
always @(posedge clock) begin
if (reset) shiftReg <= 8'h01;
else shiftReg <= {shiftReg[6:0], shiftReg[7]};
end
assign io_led = shiftReg;
endmodule
验证方法
编写测试平台LedShifterTest.scala:
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
class LedShifterTest extends AnyFlatSpec with ChiselScalatestTester {
"LedShifter" should "循环移位" in {
test(new LedShifter) { dut =>
// 复位后初始值
dut.reset.poke(true.B)
dut.clock.step(1)
dut.reset.poke(false.B)
dut.io.led.expect(0x01.U)
// 连续时钟周期观察移位
val expected = Seq(0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01)
for (v <- expected) {
dut.clock.step(1)
dut.io.led.expect(v.U)
}
println("流水灯循环移位测试通过")
}
}
}
在build.sbt中添加测试依赖后执行:
sbt test
通过条件:测试输出流水灯循环移位测试通过,且无断言失败。观察波形时,io_led应在每个时钟上升沿依次输出0x01→0x02→0x04→0x08→0x10→0x20→0x40→0x80,然后回到0x01循环。
关键说明
RegInit(0x01.U)声明了一个带同步复位的寄存器,复位值为0x01,即只有最右侧LED点亮。Cat(shiftReg(6,0), shiftReg(7))将低7位与最高位拼接,实现循环左移——最高位被移到最低位,形成环形流水。- 若需改变流水速度,可在时钟路径上插入分频计数器(本案例未包含,以保持最小实现)。