1 fifo解讀
module位置:sirv_gnrl_bufs.v
sirv_gnrl_fifo
基于vivado軟體進行測試:
sirv_gnrl_fifo.v
`define FPGA_SOURCE
//=====================================================================
//
// Designer : Bob Hu
//
// Description:
// The general sync FIFO module
//
// ====================================================================
module sirv_gnrl_fifo # (
// When the depth is 1, the ready signal may relevant to next stage's ready, hence become logic
// chains. Use CUT_READY to control it
// When fifo depth is 1, the fifo is a signle stage
// if CUT_READY is set, then the back-pressure ready signal will be cut
// off, and it can only pass 1 data every 2 cycles
// When fifo depth is > 1, then it is actually a really fifo
// The CUT_READY parameter have no impact to any logics
parameter CUT_READY = 0,
parameter MSKO = 0,// Mask out the data with valid or not
parameter DP = 8,// FIFO depth
parameter DW = 32// FIFO width
) (
input i_vld,
output i_rdy,
input [DW-1:0] i_dat,
output o_vld,
input o_rdy,
output [DW-1:0] o_dat,
input clk,
input rst_n
);
genvar i;
generate //{
if(DP == 0) begin: dp_eq1//{ pass through when it is 0 entries
assign o_vld = i_vld;
assign i_rdy = o_rdy;
assign o_dat = i_dat;
end//}
else begin: dp_gt0//{
// FIFO registers
wire [DW-1:0] fifo_rf_r [DP-1:0];
wire [DP-1:0] fifo_rf_en;
// read/write enable
wire wen = i_vld & i_rdy;
wire ren = o_vld & o_rdy;
/ Read-Pointer and Write-Pointer
wire [DP-1:0] rptr_vec_nxt;
wire [DP-1:0] rptr_vec_r;
wire [DP-1:0] wptr_vec_nxt;
wire [DP-1:0] wptr_vec_r;
if(DP == 1) begin:rptr_dp_1
assign rptr_vec_nxt = 1'b1;
end
else begin:rptr_dp_not_1
assign rptr_vec_nxt =
rptr_vec_r[DP-1] ? {{DP-1{1'b0}}, 1'b1} :
(rptr_vec_r << 1);
end
if(DP == 1) begin:wptr_dp_1
assign wptr_vec_nxt = 1'b1;
end
else begin:wptr_dp_not_1
assign wptr_vec_nxt =
wptr_vec_r[DP-1] ? {{DP-1{1'b0}}, 1'b1} :
(wptr_vec_r << 1);
end
sirv_gnrl_dfflrs #(1) rptr_vec_0_dfflrs (ren, rptr_vec_nxt[0] , rptr_vec_r[0] , clk, rst_n); // default reset to 1
sirv_gnrl_dfflrs #(1) wptr_vec_0_dfflrs (wen, wptr_vec_nxt[0] , wptr_vec_r[0] , clk, rst_n);
if(DP > 1) begin:dp_gt1
sirv_gnrl_dfflr #(DP-1) rptr_vec_31_dfflr (ren, rptr_vec_nxt[DP-1:1], rptr_vec_r[DP-1:1], clk, rst_n);
sirv_gnrl_dfflr #(DP-1) wptr_vec_31_dfflr (wen, wptr_vec_nxt[DP-1:1], wptr_vec_r[DP-1:1], clk, rst_n);
end
/ Vec register to easy full and empty and the o_vld generation with flop-clean
wire [DP:0] i_vec;
wire [DP:0] o_vec;
wire [DP:0] vec_nxt;
wire [DP:0] vec_r;
wire vec_en = (ren ^ wen );
assign vec_nxt = wen ? {vec_r[DP-1:0], 1'b1} : (vec_r >> 1);
sirv_gnrl_dfflrs #(1) vec_0_dfflrs (vec_en, vec_nxt[0] , vec_r[0] , clk, rst_n);
sirv_gnrl_dfflr #(DP) vec_31_dfflr (vec_en, vec_nxt[DP:1], vec_r[DP:1], clk, rst_n);
assign i_vec = {1'b0,vec_r[DP:1]};
assign o_vec = {1'b0,vec_r[DP:1]};
if(DP == 1) begin:cut_dp_eq1//{
if(CUT_READY == 1) begin:cut_ready//{
// If cut ready, then only accept when fifo is not full
assign i_rdy = (~i_vec[DP-1]);
end//}
else begin:no_cut_ready//{
// If not cut ready, then can accept when fifo is not full or it is popping
assign i_rdy = (~i_vec[DP-1]) | ren;
end//}
end//}
else begin : no_cut_dp_gt1//}{
assign i_rdy = (~i_vec[DP-1]);
end//}
/ write fifo
for (i=0; i<DP; i=i+1) begin:fifo_rf//{
assign fifo_rf_en[i] = wen & wptr_vec_r[i];
// Write the FIFO registers
sirv_gnrl_dffl #(DW) fifo_rf_dffl (fifo_rf_en[i], i_dat, fifo_rf_r[i], clk);
end//}
/One-Hot Mux as the read path
integer j;
reg [DW-1:0] mux_rdat;
always @*
begin : rd_port_PROC//{
mux_rdat = {DW{1'b0}};
for(j=0; j<DP; j=j+1) begin
mux_rdat = mux_rdat | ({DW{rptr_vec_r[j]}} & fifo_rf_r[j]);
end
end//}
if(MSKO == 1) begin:mask_output//{
// Mask the data with valid since the FIFO register is not reset and as X
assign o_dat = {DW{o_vld}} & mux_rdat;
end//}
else begin:no_mask_output//{
// Not Mask the data with valid since no care with X for datapth
assign o_dat = mux_rdat;
end//}
// o_vld as flop-clean
assign o_vld = (o_vec[0]);
end//}
endgenerate//}
endmodule
tb_sirv_gnrl_fifo.v測試檔案:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 04/08/2021 03:18:51 PM
// Design Name:
// Module Name: tb_sirv_gnrl_dffs
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_sirv_gnrl_dffs(
);
print_task print();
reg i_vld;
wire i_rdy;
reg [9:0] i_dat;
wire o_vld;
reg o_rdy;
wire [9:0] o_dat;
reg clk;
reg rst_n;
// clk init
parameter PERIOD = 2;
always begin
#(PERIOD/2) clk = 1;
#(PERIOD/2) clk = 0;
end
reset task
task reset_task;
input [15:0] reset_time;
begin
rst_n = 0;
#reset_time;
rst_n = 1;
end
endtask
sirv_gnrl_fifo # (
.CUT_READY (0),
.MSKO (0),
.DP (2),
.DW (10)
) u_sirv_gnrl_dffs(
.i_vld (i_vld),
.i_rdy (i_rdy),
.i_dat (i_dat),
.o_vld (o_vld),
.o_rdy (o_rdy),
.o_dat (o_dat),
.clk (clk),
.rst_n (rst_n)
);
initial begin
reset_task(20);
i_vld = 1'b0;
i_dat = 10'h00;
o_rdy = 1'b0;
# 11;
i_vld = 1'b1;
i_dat = 10'hf8;
o_rdy = 1'b1;
# 2;
i_vld = 1'b0;
i_dat = 10'h00;
o_rdy = 1'b0;
# 10;
i_vld = 1'b1;
i_dat = 10'h3d;
o_rdy = 1'b0;
# 2;
i_vld = 1'b0;
i_dat = 10'h00;
o_rdy = 1'b0;
# 2;
i_vld = 1'b0;
i_dat = 10'h00;
o_rdy = 1'b0;
# 10;
i_vld = 1'b1;
i_dat = 10'hd8;
o_rdy = 1'b1;
# 2;
i_vld = 1'b0;
i_dat = 10'h00;
o_rdy = 1'b0;
# 20;
i_vld = 1'b0;
i_dat = 10'h00;
o_rdy = 1'b1;
# 2;
i_vld = 1'b0;
i_dat = 10'h00;
o_rdy = 1'b0;
# 20;
print.terminate;
end
endmodule
還需要單獨拷貝蜂鳥工程中的 sirv_gnrl_dffs.v檔案.
測試後得到測試波形,結合波形和代碼進行分析,關鍵點:
- fifo實作的功能: 将icb總線的cmd輸入信号打包成一個package壓入FIFO, FIFO的深度設定為2,寬度為packge對應的資料寬度. 當FIFO未被壓滿時, i_rdy 信号一直保持高電平有效; 當FIFO壓滿後i_rdy拉低, 告知icb總線的master不可以壓入了. 當FIFO有資料時, o_vld保持高電平,告知icb總線的slave目前master有請求.
- 為什麼vec_r寄存器的長度為 DP+1, 比如當FIFO深度為2時,為什麼vec_r是3?
sirv_gnrl_buffer 解讀
主要由兩個fifo組成,分别處理icb_cmd 和 icb_rsq, 指令通道和回報通道的分别對應兩個fifo
sirv_icb1to16_bus
首先設定一個 sirv_gnrl_buffer對輸入的cmd和回報的rsq進行fifo狀态存儲, 然後使用sirv_gnrl_icb_splt 對sirv_gnrl_buffer 處理後的的cmd和rsq進行出去, 将其split