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循环。

时钟周期 clk LED输出 io_led 0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80 0x01 移位方向 bit7 bit0 每个时钟周期左移1位,bit7循环回bit0

关键说明

  • RegInit(0x01.U)声明了一个带同步复位的寄存器,复位值为0x01,即只有最右侧LED点亮。
  • Cat(shiftReg(6,0), shiftReg(7))将低7位与最高位拼接,实现循环左移——最高位被移到最低位,形成环形流水。
  • 若需改变流水速度,可在时钟路径上插入分频计数器(本案例未包含,以保持最小实现)。