risc-v中文社区

 找回密码
 立即注册
查看: 1633|回复: 3

[原创] BubbleFifo

  [复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2021-9-5 19:57:49 | 显示全部楼层 |阅读模式
import chisel3._
import chisel3.util._
class FifoIO[T <: Data](private val gen:T) extends Bundle {
//总结:enq是取反方向,deq是正常信号方向
  val enq = Flipped(new DecoupledIO[T](gen))   //DecoupledIO-->>ReadyValidIO-->>Bundle  是带有valid和ready的复杂信号  Flipped则将bits,ready和valid信号切换方向
  val deq = new DecoupledIO[T](gen) //deq是正常的bits,ready,valid方向
}
abstract class Fifo[T <: Data](gen:T,depth:Int) extends Module {  //带有valid和ready的FIFO,并且有二个“group”,一个是enq,一个是deq
  val io = IO(new FifoIO[T](gen))
  assert(depth > 0,"Number of buffer elements needs to be larger than 0")
}
import chisel3._
class BubbleFifo[T <: Data](gen:T,depth:Int) extends Fifo(gen,depth) { outer=> //通过继承产生硬件
  private class Buffer extends Module { //带enq/deq端口 full标志及data寄存器
    val io = IO(new FifoIO(gen)) //FifoIO带enq/deq端口组,组中带有valid/ready信号的Bundle ,enq的ready/valid与正常的ready/valid是反向的,也就是说enq的valid是input,deq的ready是output
    val fullReg = RegInit(false.B) //满 标志
    val dataReq = Reg(gen)  //数据寄存器
    when (fullReg) {
      when (io.deq.ready) { //deq是正常的valid(output)/ready(input),类似AXI master的valid/ready
        fullReg := false.B  //也就是说 full且收到指令ready情况就会发送数据出去,当然fullReg要清标志
      }
    } .otherwise{
      when(io.enq.valid) { //enq.valid是输入
        //对方发来的valid有效
        fullReg := true.B
        dataReq := io.enq.bits //fifo的数据取至enq端口组中的bits
      }
    }
  //io.enq是被Flipped一次,即enq.ready是output,而enq.valid是input,也就是说enq是从机端口
    io.enq.ready := !fullReg //只要不是满的就发出ready
    io.deq.valid := fullReg  //deq是主机端口,只要是满的就发出valid数据有效信号
    io.deq.bits := dataReq   //主机端口的数据deq.bits来至dataReg即
  }
  private val buffers = Array.fill(depth){Module(new Buffer())} //深度为depth的Buffer
  for(i <- 0 until depth - 1) {  //[0~ (depth-1) )即[0~ depth-2 ]
    buffers(i+1).io.enq <> buffers(i).io.deq  //enq.ready(output)连deq.ready(input),enq.valid连deq.valid,总的原则:同级相连,input=>output,output->input,即enq->deq,deq->enq
    //verilog中代码:
    // wire Buffer_2_io_enq_ready
    // wire Buffer_1_io_deq_ready
    // wire Buffer_2_io_enq_valid
    // wire Buffer_1_io_deq_valid
    // Buffer_1_io_deq_ready(input) = Buffer_2_io_enq_ready(output)
    //Buffer_1_io_enq_valid(input) = Buffer_io_deq_valid(output)
    //Buffer_2_io_enq_valid(input) = Buffer_1_io_deq_valid(output)
  }
  //整体连接<>,用于正常端口和Flipped端口之间的连接。整体连接将左右两边的端口列表里所有同名的端口进行连接,同一级的端口
  //必须是输入连输出,输出连输入;父级和子级连则输入连输入,输出连输出。
  //另外,不仅仅要求方向如上要求,而且还要求端口名称、数量、类型都要相同。

  //BubbleFifo的io.enq相当于AXI的SLAVE,而deq相当于AXI的MASTER
  //io.enq.valid是input:input io_enq_valid      assign Buffer_io_enq_valid(input) = io_enq_valid(input); 父子之间input连input
  //io.enq.bits是input:  input  [3:0] io_enq_bits    assign  Buffer_io_enq_bits = io_enq_bits 父子之间input连input
  //而io.enq.ready是output,经过<>连接之后产生的verilog代码:
  // output io_enq_reqady
  // wire Buffer_io_enq_ready
  // assign io_enq_ready(output) = Buffer_io_enq_ready(output)父子级之间output连output
  io.enq <> buffers(0).io.enq //总的原则是ready->ready,valid->valid,bits->bits,因为是父子级连,需要input->input,output->output,所以只能是enq->enq,deq->deq

  //父子级相连,只能是input->input,output->output,即enq->enq,deq->deq
  // input io_deq_reaqdy
  // output io_deq_valid
  // output[3:0] io_deq_bits
  // wire Buffer_4_io_deq_ready
  // wire Buffer_4_io_deq_valid
  // wire[3:0] Buffer_4_io_deq_bits
  // assign Buffer_4_io_deq_ready = io_deq_ready
  //assign io_deq_valid = Buffer_4_io_deq_valid
  //assing io_deq_bits = Buffer_4_io_deq_bits
  io.deq <> buffers(depth - 1).io.deq
}



回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-9-5 19:59:03 | 显示全部楼层
对应的verilog文件内容如下:
module Buffer(
  input        clock,
  input        reset,
  output       io_enq_ready,
  input        io_enq_valid,
  input  [3:0] io_enq_bits,
  input        io_deq_ready,
  output       io_deq_valid,
  output [3:0] io_deq_bits
);
  reg  fullReg; // @[BubbleFifo.scala 7:26]
  reg [3:0] dataReq; // @[BubbleFifo.scala 8:22]
  wire  _GEN_1 = io_enq_valid | fullReg; // @[BubbleFifo.scala 14:26]
  assign io_enq_ready = ~fullReg; // @[BubbleFifo.scala 21:18]
  assign io_deq_valid = fullReg; // @[BubbleFifo.scala 22:18]
  assign io_deq_bits = dataReq; // @[BubbleFifo.scala 23:17]

  always @(posedge clock) begin
    if (reset) begin
      fullReg <= 1'h0;
    end else if (fullReg) begin
      if (io_deq_ready) begin
        fullReg <= 1'h0;
      end
    end else begin
      fullReg <= _GEN_1;
    end
    if (!(fullReg)) begin
      if (io_enq_valid) begin
        dataReq <= io_enq_bits;
      end
    end
  end
endmodule
module BubbleFifo(
  input        clock,
  input        reset,
  output       io_enq_ready,
  input        io_enq_valid,
  input  [3:0] io_enq_bits,
  input        io_deq_ready,
  output       io_deq_valid,
  output [3:0] io_deq_bits
);
  wire  Buffer_clock; // @[BubbleFifo.scala 25:49]
  wire  Buffer_reset; // @[BubbleFifo.scala 25:49]
  wire  Buffer_io_enq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_io_enq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_io_enq_bits; // @[BubbleFifo.scala 25:49]
  wire  Buffer_io_deq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_io_deq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_io_deq_bits; // @[BubbleFifo.scala 25:49]
  wire  Buffer_1_clock; // @[BubbleFifo.scala 25:49]
  wire  Buffer_1_reset; // @[BubbleFifo.scala 25:49]
  wire  Buffer_1_io_enq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_1_io_enq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_1_io_enq_bits; // @[BubbleFifo.scala 25:49]
  wire  Buffer_1_io_deq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_1_io_deq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_1_io_deq_bits; // @[BubbleFifo.scala 25:49]
  wire  Buffer_2_clock; // @[BubbleFifo.scala 25:49]
  wire  Buffer_2_reset; // @[BubbleFifo.scala 25:49]
  wire  Buffer_2_io_enq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_2_io_enq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_2_io_enq_bits; // @[BubbleFifo.scala 25:49]
  wire  Buffer_2_io_deq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_2_io_deq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_2_io_deq_bits; // @[BubbleFifo.scala 25:49]
  wire  Buffer_3_clock; // @[BubbleFifo.scala 25:49]
  wire  Buffer_3_reset; // @[BubbleFifo.scala 25:49]
  wire  Buffer_3_io_enq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_3_io_enq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_3_io_enq_bits; // @[BubbleFifo.scala 25:49]
  wire  Buffer_3_io_deq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_3_io_deq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_3_io_deq_bits; // @[BubbleFifo.scala 25:49]
  wire  Buffer_4_clock; // @[BubbleFifo.scala 25:49]
  wire  Buffer_4_reset; // @[BubbleFifo.scala 25:49]
  wire  Buffer_4_io_enq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_4_io_enq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_4_io_enq_bits; // @[BubbleFifo.scala 25:49]
  wire  Buffer_4_io_deq_ready; // @[BubbleFifo.scala 25:49]
  wire  Buffer_4_io_deq_valid; // @[BubbleFifo.scala 25:49]
  wire [3:0] Buffer_4_io_deq_bits; // @[BubbleFifo.scala 25:49]
  Buffer Buffer ( // @[BubbleFifo.scala 25:49]
    .clock(Buffer_clock),
    .reset(Buffer_reset),
    .io_enq_ready(Buffer_io_enq_ready),
    .io_enq_valid(Buffer_io_enq_valid),
    .io_enq_bits(Buffer_io_enq_bits),
    .io_deq_ready(Buffer_io_deq_ready),
    .io_deq_valid(Buffer_io_deq_valid),
    .io_deq_bits(Buffer_io_deq_bits)
  );
  Buffer Buffer_1 ( // @[BubbleFifo.scala 25:49]
    .clock(Buffer_1_clock),
    .reset(Buffer_1_reset),
    .io_enq_ready(Buffer_1_io_enq_ready),
    .io_enq_valid(Buffer_1_io_enq_valid),
    .io_enq_bits(Buffer_1_io_enq_bits),
    .io_deq_ready(Buffer_1_io_deq_ready),
    .io_deq_valid(Buffer_1_io_deq_valid),
    .io_deq_bits(Buffer_1_io_deq_bits)
  );
  Buffer Buffer_2 ( // @[BubbleFifo.scala 25:49]
    .clock(Buffer_2_clock),
    .reset(Buffer_2_reset),
    .io_enq_ready(Buffer_2_io_enq_ready),
    .io_enq_valid(Buffer_2_io_enq_valid),
    .io_enq_bits(Buffer_2_io_enq_bits),
    .io_deq_ready(Buffer_2_io_deq_ready),
    .io_deq_valid(Buffer_2_io_deq_valid),
    .io_deq_bits(Buffer_2_io_deq_bits)
  );
  Buffer Buffer_3 ( // @[BubbleFifo.scala 25:49]
    .clock(Buffer_3_clock),
    .reset(Buffer_3_reset),
    .io_enq_ready(Buffer_3_io_enq_ready),
    .io_enq_valid(Buffer_3_io_enq_valid),
    .io_enq_bits(Buffer_3_io_enq_bits),
    .io_deq_ready(Buffer_3_io_deq_ready),
    .io_deq_valid(Buffer_3_io_deq_valid),
    .io_deq_bits(Buffer_3_io_deq_bits)
  );
  Buffer Buffer_4 ( // @[BubbleFifo.scala 25:49]
    .clock(Buffer_4_clock),
    .reset(Buffer_4_reset),
    .io_enq_ready(Buffer_4_io_enq_ready),
    .io_enq_valid(Buffer_4_io_enq_valid),
    .io_enq_bits(Buffer_4_io_enq_bits),
    .io_deq_ready(Buffer_4_io_deq_ready),
    .io_deq_valid(Buffer_4_io_deq_valid),
    .io_deq_bits(Buffer_4_io_deq_bits)
  );
  assign io_enq_ready = Buffer_io_enq_ready; // @[BubbleFifo.scala 41:10]
  assign io_deq_valid = Buffer_4_io_deq_valid; // @[BubbleFifo.scala 49:10]
  assign io_deq_bits = Buffer_4_io_deq_bits; // @[BubbleFifo.scala 49:10]
  assign Buffer_clock = clock;
  assign Buffer_reset = reset;
  assign Buffer_io_enq_valid = io_enq_valid; // @[BubbleFifo.scala 41:10]
  assign Buffer_io_enq_bits = io_enq_bits; // @[BubbleFifo.scala 41:10]
  assign Buffer_io_deq_ready = Buffer_1_io_enq_ready; // @[BubbleFifo.scala 27:25]
  assign Buffer_1_clock = clock;
  assign Buffer_1_reset = reset;
  assign Buffer_1_io_enq_valid = Buffer_io_deq_valid; // @[BubbleFifo.scala 27:25]
  assign Buffer_1_io_enq_bits = Buffer_io_deq_bits; // @[BubbleFifo.scala 27:25]
  assign Buffer_1_io_deq_ready = Buffer_2_io_enq_ready; // @[BubbleFifo.scala 27:25]
  assign Buffer_2_clock = clock;
  assign Buffer_2_reset = reset;
  assign Buffer_2_io_enq_valid = Buffer_1_io_deq_valid; // @[BubbleFifo.scala 27:25]
  assign Buffer_2_io_enq_bits = Buffer_1_io_deq_bits; // @[BubbleFifo.scala 27:25]
  assign Buffer_2_io_deq_ready = Buffer_3_io_enq_ready; // @[BubbleFifo.scala 27:25]
  assign Buffer_3_clock = clock;
  assign Buffer_3_reset = reset;
  assign Buffer_3_io_enq_valid = Buffer_2_io_deq_valid; // @[BubbleFifo.scala 27:25]
  assign Buffer_3_io_enq_bits = Buffer_2_io_deq_bits; // @[BubbleFifo.scala 27:25]
  assign Buffer_3_io_deq_ready = Buffer_4_io_enq_ready; // @[BubbleFifo.scala 27:25]
  assign Buffer_4_clock = clock;
  assign Buffer_4_reset = reset;
  assign Buffer_4_io_enq_valid = Buffer_3_io_deq_valid; // @[BubbleFifo.scala 27:25]
  assign Buffer_4_io_enq_bits = Buffer_3_io_deq_bits; // @[BubbleFifo.scala 27:25]
  assign Buffer_4_io_deq_ready = io_deq_ready; // @[BubbleFifo.scala 49:10]
endmodule
回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-9-6 13:53:49 | 显示全部楼层
针对:io.enq <> buffers(0).io.enq //总的原则是ready->ready,valid->valid,bits->bits,因为是父子级连,需要input->input,output->output,所以只能是enq->enq,deq->deq
这一句整体连接代码,如果我将代码修改为:buffers(0).io.enq <> io.enq结果发现生成的verilog代码是一样的,还是:
assign io_enq_ready = Buffer_io_enq_ready   //父output类型 = 子output类型的赋值形式
assign Buffer_io_enq_valid = io_enq_valid //子input类型 = 父input类型赋值形式
assign Buffer_io_enq_bits = io_enq_bitss //子input类型 = 父input类型赋值形式
总结起来就是说:父子相连的整体连接,父output=子output,子input=父input
形象来理解:输入给父的信号肯定是要输入给子的,子要输出的肯定是要通过父才能输出的
回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-9-6 15:06:56 | 显示全部楼层
buffers(i+1).io.enq <> buffers(i).io.deq这一句改为:buffers(i).io.deq <>  buffers(i+1).io.enq ,结果生成的verilog还是一样的。
这说明同级模块之间整体连接也不是依赖谁在左边谁在右边书写。

对应verilog中赋值时都是assint input类型 = output类型,其实也可以形象理解:同级模块之间互连对外层模块来说都是内部互连,
output不会是连到外层模块之外,只能是output输出给内部的input,内部input也只能是其它内部模块的output输出来。







回复

使用道具 举报

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

本版积分规则



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

GMT+8, 2024-4-29 12:01 , Processed in 0.033865 second(s), 17 queries .

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

Copyright © 2018-2021, risc-v open source

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