Chisel 学习笔记(七)

本文深入探讨了Chisel硬件描述语言中集合的使用,重点介绍了List、Seq、ArrayBuffer和专为Chisel设计的Vec集合的特性和应用场景。通过具体案例,如RISC-V寄存器堆的设计,展示了不同集合类型在硬件模块参数传递和状态存储中的优势。

Chisel 学习笔记(七)

集合

在Chisel中,我们既可以使用Scala中自带的集合,包括List,Seq,ArrayBuffer——List的使用方式在学习笔记(一)中有所体现;Seq与List类似,但是在Chisel中,我们更常使用Seq来表述某个模块的参数;ArrayBuffer的特性是不用描述出长度,且通过+就可以简单的添加元素(-可以删除元素),较为方便——也可以使用Chisel中所有的特殊集合Vec,Vec与其他Scala中的集合功能类似,但是可以更贴合Chisel。

List,Seq,ArrayBuffer

正如上文所说

  1. List是最原初的列表类,当然也有各种操作,不过较为繁琐
  2. Seq经常作为Chisel中构造函数的参数
  3. ArrayBuffer有着更简便的对集合的操作

List&Seq

class ScalaFirFilter(taps: Seq[Int]) {
  var pseudoRegisters = List.fill(taps.length)(0)		//构造一个taps.length长度的数组,将初始设为0

  def poke(value: Int): Int = {
    pseudoRegisters = value :: pseudoRegisters.take(taps.length - 1)	//取出pseudoRegister中前taps.length-1个元素,并在列表头插入value的值
    var accumulator = 0
    for(i <- taps.indices) {
      accumulator += taps(i) * pseudoRegisters(i)	//对Seq和List中元素的访问方式一样
    }
    accumulator
  }
}

Seq&ArrayBuffer

在Chisel中,更常用的是通过Seq传参

class MyManyElementFir(consts: Seq[Int], bitWidth: Int) extends Module {	//参数为一个不定长的Seq集合
  val io = IO(new Bundle {
    val in = Input(UInt(bitWidth.W))
    val out = Output(UInt(bitWidth.W))
  })

  val regs = mutable.ArrayBuffer[UInt]()	//ArrayBuffer的使用,先初始化成空
  for(i <- 0 until consts.length) {
      if(i == 0) regs += io.in							//通过加法可以很方便地添加元素到ArrayBuffer末尾
      else       regs += RegNext(regs(i - 1), 0.U)
  }
  
  val muls = mutable.ArrayBuffer[UInt]()
  for(i <- 0 until consts.length) {
      muls += regs(i) * consts(i).U
  }

  val scan = mutable.ArrayBuffer[UInt]()
  for(i <- 0 until consts.length) {
      if(i == 0) scan += muls(i)
      else scan += muls(i) + scan(i - 1)		//对元素的访问与Seq,List一样
  }

  io.out := scan.last
}

Chisel的特性——Vec

Vec也是集合,且是为Chisel专门打造的。在某些情况下,scala中的集合并不支持Chisel的操作,主要是以下两种情况:

  1. 在Bundle中,特别是IO Bundle中,scala中的集合不再起作用
  2. 在某些需要用到Chisel特性进行访问或更改的操作中,例如处理器的寄存器堆设计,scala中的集合不再起作用

Vec的使用如下

class MyManyDynamicElementVecFir(length: Int) extends Module {
 val io = IO(new Bundle {
   val in = Input(UInt(8.W))
   val out = Output(UInt(8.W))
   val consts = Input(Vec(length, UInt(8.W)))
 })

 val regs = RegInit(Vec.fill(length - 1)(0.U(8.W)))	//对Vec的初始化和List操作类似,说明长度和初始值
//val regs = RegInit(VecInit(Seq.fill(length - 1)(0.U(8.W))))    最新一版中的Vec初始化要这样写
 for(i <- 0 until length - 1) {
     if(i == 0) regs(i) := io.in									//对Vec中元素的访问也和List一样
     else       regs(i) := regs(i - 1)
 }
 
 val muls = Wire(Vec(length, UInt(8.W)))		//对一组导线的定义
 for(i <- 0 until length) {
     if(i == 0) muls(i) := io.in * io.consts(i)
     else       muls(i) := regs(i - 1) * io.consts(i)
 }

 val scan = Wire(Vec(length, UInt(8.W)))
 for(i <- 0 until length) {
     if(i == 0) scan(i) := muls(i)
     else scan(i) := muls(i) + scan(i - 1)
 }

 io.out := scan(length - 1)
}

RISC-V中寄存器堆的实现

package Passthrough

import chisel3._

class RegisterFile (readPorts: Int) extends Module{
 val io = IO(new Bundle{
   val wen = Input(Bool())
   val waddr = Input(UInt(5.W))
   val wdata = Input(UInt(32.W))
   val raddr = Input(Vec(readPorts, UInt(5.W)))
   val rdata = Output(Vec(readPorts, UInt(32.W)))
 })

//  val regs = RegInit(Vec(32, UInt(32.W)).fromBits(0.U)) 另外一种初始化方法
 val regs = RegInit(VecInit(Seq.fill(32)(0.U(32.W))))

 when(io.wen & io.waddr=/=0.U){
   regs(io.waddr) := io.wdata
 }

 for(i<-0 until readPorts){
   io.rdata(i) := regs(io.raddr(i))
 }

}

转载于:https://www.cnblogs.com/JamesDYX/p/10082385.html

<think>嗯,用户想了解关于Chisel电路学习的每日一练。首先,我需要确认用户对Chisel的熟悉程度。可能他们刚开始学习,或者已经有一定基础,想通过每日练习来巩固知识。Chisel是构建在Scala上的硬件构造语言,所以可能需要结合Scala的基础知识。用户可能希望得到结构化的学习计划,包含每日的小练习,逐步深入。 接下来,我应该考虑如何组织内容。每日一练通常需要从简单到复杂,覆盖Chisel的核心概念,比如组合逻辑、时序电路、模块化设计、测试等。每天一个主题,配合代码示例和练习题目,这样用户可以动手实践。同时,要确保符合用户的要求,使用正确的中文和LaTeX格式,行内公式用$...$,独立公式用$$...$$。 另外,用户可能需要实际例子来理解概念,比如如何用Chisel实现一个加法器或状态机。测试部分也很重要,因为ChiselTest是常用的测试框架,应该包含如何编写测试用例。最后,高级主题如参数化设计、生成Verilog代码、性能优化可能适合后续的练习。 需要检查是否有遗漏的部分,比如安装配置环境,或者参考资料推荐。但用户可能已经具备基本环境,所以重点放在每日练习内容上。同时,结构要清晰,分点说明,每个练习日包含目标、示例代码和练习任务,让用户逐步完成。</think>以下是为Chisel硬件设计语言学习者设计的"每日一练"渐进式学习方案,采用问题导向型结构,结合关键知识点和代码示例: 🌟 **Day 1:基础逻辑门实现** ```scala class ANDgate extends Module { val io = IO(new Bundle { val a = Input(Bool()) val b = Input(Bool()) val out = Output(Bool()) }) io.out := io.a & io.b // 实现与门逻辑 } ``` 练习:扩展实现OR/XOR/NAND门电路 🔢 **Day 2:组合逻辑设计** 实现4位全加器: ```scala class FullAdder extends Module { val io = IO(new Bundle { val a = Input(UInt(1.W)) val b = Input(UInt(1.W)) val cin = Input(UInt(1.W)) val sum = Output(UInt(1.W)) val cout = Output(UInt(1.W)) }) io.sum := io.a ^ io.b ^ io.cin io.cout := (io.a & io.b) | (io.a & io.cin) | (io.b & io.cin) } ``` 练习:构建级联的4位行波进位加法器 ⏳ **Day 3:时序电路设计** 实现带异步复位的D触发器: ```scala class DFFAsyncReset extends Module { val io = IO(new Bundle { val d = Input(Bool()) val rst = Input(Bool()) val q = Output(Bool()) }) io.q := withReset(io.rst)(RegNext(io.d, false.B)) } ``` 练习:设计4位循环移位寄存器 📦 **Day 4:模块化设计** 构建计数器模块: ```scala class Counter(mod: Int) extends Module { val io = IO(new Bundle { val en = Input(Bool()) val out = Output(UInt(log2Ceil(mod).W)) }) val count = RegInit(0.U(log2Ceil(mod).W)) when(io.en) { count := Mux(count === (mod-1).U, 0.U, count + 1.U) } io.out := count } ``` 练习:实现可配置位宽的计数器 📊 **Day 5:总线接口设计** 定义APB总线接口: ```scala class APBBundle extends Bundle { val paddr = Output(UInt(32.W)) val psel = Output(Bool()) val penable = Output(Bool()) val pwrite = Output(Bool()) val pwdata = Output(UInt(32.W)) val prdata = Input(UInt(32.W)) val pready = Input(Bool()) } ``` 练习:实现APB总线转接器 🔍 **Day 6:测试验证** 使用ChiselTest进行模块验证: ```scala test(new ANDgate).withAnnotations(Seq(WriteVcdAnnotation)) { c => c.io.a.poke(false.B) c.io.b.poke(true.B) c.io.out.expect(false.B) c.clock.step() } ``` 练习:为计数器模块编写完整测试用例 💡 **高阶练习建议**: 1. 参数化FIR滤波器设计 2. RISC-V核心流水线实现 3. AXI4总线协议转换器 4. 动态时钟门控电路 5. 异步FIFO缓冲设计 📚 **学习资源推荐**: 1. 官方文档:https://www.chisel-lang.org/ 2. 数字设计实践工具链安装: ```bash brew install verilator # macOS sudo apt install verilator gtkwave # Ubuntu ``` 3. 在线实验平台:https://www.myhdl.org/chisel-edu/ 每日练习建议流程: 1. 理解当日设计目标 2. 编写Chisel代码 3. 生成Verilog:`sbt run` 4. 使用Verilator进行仿真验证 5. 记录设计参数和时序分析 通过持续练习,您将逐步掌握: - 硬件描述语言的抽象建模能力 - 数字系统架构设计方法 - 可重用IP核开发技巧 - 硬件/软件协同验证流程 建议每天投入1-2小时实践,遇到问题可通过Chisel社区(https://github.com/chipsalliance/chisel/discussions)交流讨论。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值