joe 发表于 2021-9-8 11:21:51

与xilin或alter的fifo相连的chisel BubbleFIFO源码及注释

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
}


joe 发表于 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)
}
}


页: [1]
查看完整版本: 与xilin或alter的fifo相连的chisel BubbleFIFO源码及注释