joe 发表于 2021-9-5 19:57:49

BubbleFifo

import chisel3._
import chisel3.util._
class FifoIO(private val gen:T) extends Bundle {
//总结:enq是取反方向,deq是正常信号方向
val enq = Flipped(new DecoupledIO(gen))   //DecoupledIO-->>ReadyValidIO-->>Bundle是带有valid和ready的复杂信号Flipped则将bits,ready和valid信号切换方向
val deq = new DecoupledIO(gen) //deq是正常的bits,ready,valid方向
}
abstract class Fifo(gen:T,depth:Int) extends Module {//带有valid和ready的FIFO,并且有二个“group”,一个是enq,一个是deq
val io = IO(new FifoIO(gen))
assert(depth > 0,"Number of buffer elements needs to be larger than 0")
}
import chisel3._
class BubbleFifo(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) {//
    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 io_enq_bits    assignBuffer_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 io_deq_bits
// wire Buffer_4_io_deq_ready
// wire Buffer_4_io_deq_valid
// wire 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
}



joe 发表于 2021-9-5 19:59:03

对应的verilog文件内容如下:
module Buffer(
input      clock,
input      reset,
output       io_enq_ready,
input      io_enq_valid,
input io_enq_bits,
input      io_deq_ready,
output       io_deq_valid,
output io_deq_bits
);
regfullReg; // @
reg dataReq; // @
wire_GEN_1 = io_enq_valid | fullReg; // @
assign io_enq_ready = ~fullReg; // @
assign io_deq_valid = fullReg; // @
assign io_deq_bits = dataReq; // @

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 io_enq_bits,
input      io_deq_ready,
output       io_deq_valid,
output io_deq_bits
);
wireBuffer_clock; // @
wireBuffer_reset; // @
wireBuffer_io_enq_ready; // @
wireBuffer_io_enq_valid; // @
wire Buffer_io_enq_bits; // @
wireBuffer_io_deq_ready; // @
wireBuffer_io_deq_valid; // @
wire Buffer_io_deq_bits; // @
wireBuffer_1_clock; // @
wireBuffer_1_reset; // @
wireBuffer_1_io_enq_ready; // @
wireBuffer_1_io_enq_valid; // @
wire Buffer_1_io_enq_bits; // @
wireBuffer_1_io_deq_ready; // @
wireBuffer_1_io_deq_valid; // @
wire Buffer_1_io_deq_bits; // @
wireBuffer_2_clock; // @
wireBuffer_2_reset; // @
wireBuffer_2_io_enq_ready; // @
wireBuffer_2_io_enq_valid; // @
wire Buffer_2_io_enq_bits; // @
wireBuffer_2_io_deq_ready; // @
wireBuffer_2_io_deq_valid; // @
wire Buffer_2_io_deq_bits; // @
wireBuffer_3_clock; // @
wireBuffer_3_reset; // @
wireBuffer_3_io_enq_ready; // @
wireBuffer_3_io_enq_valid; // @
wire Buffer_3_io_enq_bits; // @
wireBuffer_3_io_deq_ready; // @
wireBuffer_3_io_deq_valid; // @
wire Buffer_3_io_deq_bits; // @
wireBuffer_4_clock; // @
wireBuffer_4_reset; // @
wireBuffer_4_io_enq_ready; // @
wireBuffer_4_io_enq_valid; // @
wire Buffer_4_io_enq_bits; // @
wireBuffer_4_io_deq_ready; // @
wireBuffer_4_io_deq_valid; // @
wire Buffer_4_io_deq_bits; // @
Buffer Buffer ( // @
    .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 ( // @
    .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 ( // @
    .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 ( // @
    .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 ( // @
    .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; // @
assign io_deq_valid = Buffer_4_io_deq_valid; // @
assign io_deq_bits = Buffer_4_io_deq_bits; // @
assign Buffer_clock = clock;
assign Buffer_reset = reset;
assign Buffer_io_enq_valid = io_enq_valid; // @
assign Buffer_io_enq_bits = io_enq_bits; // @
assign Buffer_io_deq_ready = Buffer_1_io_enq_ready; // @
assign Buffer_1_clock = clock;
assign Buffer_1_reset = reset;
assign Buffer_1_io_enq_valid = Buffer_io_deq_valid; // @
assign Buffer_1_io_enq_bits = Buffer_io_deq_bits; // @
assign Buffer_1_io_deq_ready = Buffer_2_io_enq_ready; // @
assign Buffer_2_clock = clock;
assign Buffer_2_reset = reset;
assign Buffer_2_io_enq_valid = Buffer_1_io_deq_valid; // @
assign Buffer_2_io_enq_bits = Buffer_1_io_deq_bits; // @
assign Buffer_2_io_deq_ready = Buffer_3_io_enq_ready; // @
assign Buffer_3_clock = clock;
assign Buffer_3_reset = reset;
assign Buffer_3_io_enq_valid = Buffer_2_io_deq_valid; // @
assign Buffer_3_io_enq_bits = Buffer_2_io_deq_bits; // @
assign Buffer_3_io_deq_ready = Buffer_4_io_enq_ready; // @
assign Buffer_4_clock = clock;
assign Buffer_4_reset = reset;
assign Buffer_4_io_enq_valid = Buffer_3_io_deq_valid; // @
assign Buffer_4_io_enq_bits = Buffer_3_io_deq_bits; // @
assign Buffer_4_io_deq_ready = io_deq_ready; // @
endmodule

joe 发表于 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
形象来理解:输入给父的信号肯定是要输入给子的,子要输出的肯定是要通过父才能输出的

joe 发表于 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输出来。







页: [1]
查看完整版本: BubbleFifo