risc-v中文社区

 找回密码
 立即注册
查看: 994|回复: 1

[原创] 与xilin或alter的fifo相连的chisel BubbleFIFO源码及注释

[复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2021-9-8 11:21:51 | 显示全部楼层 |阅读模式
import chisel3._
import chisel3.util._

/**
  * 本代码可以与xilinx或alter的FPGA FIFO结合使用
  * Alter's FIFO component:
  * data - data in, q - data out, wrreq and rdreq
  * state: full and empty
  *
  * Xilinx's FIFO component:
  * din and dout, wr_en, rd_en
  * state: full and empty
  */
class WriterIO(size:Int) extends Bundle {  //定义写FIFO的端口Bundle,有三个信号  此WriterIO就是用于接收Master给本模块发数据
  val write = Input(Bool()) //写指示
  val full = Output(Bool()) //写满
  val din = Input(UInt(size.W)) //写的数据  size是指数据位宽
}
class ReaderIO(size:Int) extends Bundle { //定义读FIFO的端口Bundle,也是三个信号 此ReaderIO用于给下游Slave发数据
  val read = Input(Bool()) //读指示
  val empty = Output(Bool()) //空标志
  val dout = Output(UInt(size.W))
}
class FifoRegister(size:Int) extends Module {
  val io = IO(new Bundle {
    val enq = new WriterIO(size) //因为enq用来给本模块写入数据,所以enq的对面相当于是Master
    val deq = new ReaderIO(size)
  })
  val empty :: full :: Nil = Enum(2)
  val stateReg = RegInit(empty)
  val dataReg = RegInit(0.U(size.W))

  when(stateReg === empty) { //如果空
    when(io.enq.write) { //指示写
      stateReg := full //进入满状态 ?????怎么一次写就进入满状态??? 只要deq的对方即slave将read指示始终发出则不会满
      dataReg := io.enq.din
    }
  }.elsewhen(stateReg === full) {
    when(io.deq.read) { //收到读指示
      stateReg := empty //进入empty状态
      dataReg := dataReg  //0.U just to better see empty slots in the waveform
    }
  }.otherwise{
    // There should not be an otherwise state
  }
  io.enq.full := (stateReg === full)
  io.deq.empty := (stateReg === empty)
  io.deq.dout := dataReg
}
class BubbleFifoWithXILINXALTER(size:Int,depth:Int) extends Module { //主模块
  val io = IO(new Bundle { //主模块也需要有enq和deq接口,用于和上下游模块通信
    val enq = new WriterIO(size)
    val deq = new ReaderIO(size)
  })
  assert(depth>=2,"depth>=2")
  val buffers = Array.fill(depth)(Module(new FifoRegister(size))) //缓冲区,深度为depth,元素类型为FifoRegister,实质是位宽为size的数据
  for(i <- 0 until depth-1) {
    buffers(i+1).io.enq.din := buffers(i).io.deq.dout //缓冲区中下一个元素的输入的数据来自前一个元素的输出 线成一个链条
    buffers(i+1).io.enq.write := ~buffers(i).io.deq.empty //前一个元素不空则下一个元素就可以启动写指示
    buffers(i).io.deq.read := ~buffers(i+1).io.enq.full //下一个元素的enq不满则前一个元素的读指示启动
  }
  //父子级连,只能是input连input,output连output,生成的verilog伪代码如下:
  //buffers(0).io.enq.write := io.enq.write
  //buffers(0).io.enq.din := io.enq.din
  //io.enq.full := buffers(0).io.enq.full
  io.enq <> buffers(0).io.enq
  //父子级连 生成的verilog伪代码如下
  //buffers(depth-1).io.deq.read := io.deq.read
  //io.deq.empty := buffers(depth-1).io.deq.empty
  //io.deq.dout := buffers(depth-1).io.deq.dout
  io.deq <> buffers(depth-1).io.deq
}


回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-9-8 11:26:23 | 显示全部楼层
可产生波形测试文件的iotesters测试代码:
import chisel3._
import chisel3.iotesters.PeekPokeTester

/**
* Test the design.
*/
class FifoTester(dut: BubbleFifo) extends PeekPokeTester(dut) {

  // some defaults for all signals
  poke(dut.io.enq.din, 0xab)
  poke(dut.io.enq.write, 0)
  poke(dut.io.deq.read, 0)
  step(1)
  var full = peek(dut.io.enq.full)
  var empty = peek(dut.io.deq.empty)

  // write into the buffer
  poke(dut.io.enq.din, 0x12)
  poke(dut.io.enq.write, 1)
  step(1)
  full = peek(dut.io.enq.full)

  poke(dut.io.enq.din, 0xff)
  poke(dut.io.enq.write, 0)
  step(1)
  full = peek(dut.io.enq.full)

  step(3) // see the bubbling of the first element

  // Fill the whole buffer with a check for full condition
  // Only every second cycle a write can happen.
  for (i <- 0 until 7) {
    full = peek(dut.io.enq.full)
    poke(dut.io.enq.din, 0x80 + i)
    if (full == 0) {
      poke(dut.io.enq.write, 1)
    } else {
      poke(dut.io.enq.write, 0)
    }
    step(1)
  }

  // Now we know it is full, so do a single read and watch
  // how this empty slot bubble up to the FIFO input.
  poke(dut.io.deq.read, 1)
  step(1)
  poke(dut.io.deq.read, 0)
  step(6)

  // New read out the whole buffer.
  // Also watch that maximum read out is every second clock cycle
  for (i <- 0 until 7) {
    empty = peek(dut.io.deq.empty)
    if (empty == 0) {
      poke(dut.io.deq.read, 1)
    } else {
      poke(dut.io.deq.read, 0)
    }
    step(1)
  }

  // Now write and read at maximum speed for some time
  for (i <- 1 until 16) {
    full = peek(dut.io.enq.full)
    poke(dut.io.enq.din, i)
    if (full == 0) {
      poke(dut.io.enq.write, 1)
    } else {
      poke(dut.io.enq.write, 0)
    }
    empty = peek(dut.io.deq.empty)
    if (empty == 0) {
      poke(dut.io.deq.read, 1)
    } else {
      poke(dut.io.deq.read, 0)
    }
    step(1)
  }

}

object FifoTester extends App {
  iotesters.Driver.execute(Array("--target-dir", "generated", "--generate-vcd-output", "on"), () => new BubbleFifoWithXILINXALTER(8, 4)) {
  // iotesters.Driver.execute(Array("--target-dir", "generated", "--fint-write-vcd", "--wave-form-file-name", "generated/BubbleFifoWithXILINXALTER.vcd"), () => new BubbleFifoWithXILINXALTER(8, 4)) {
    c => new FifoTester(c)
  }
}


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



Archiver|手机版|小黑屋|risc-v中文社区

GMT+8, 2024-5-3 07:36 , Processed in 0.015283 second(s), 17 queries .

risc-v中文社区论坛 官方网站

Copyright © 2018-2021, risc-v open source

快速回复 返回顶部 返回列表