試しにUltraScale+のFIFO36E2の確認をした。
下図は次作FIFOのシミュレーション波形です。
RD信号をアサートしたらデータが出てくるのではなくたいてい、こういうFIFOが欲しい。
今までは自作FIFOを使うことが多かったのですがFIFO36E2に置き換えてみようと確認してみました。
このテストベンチは自作FIFOのテストベンチです。
`timescale 1ns / 1ps
module tb_sample_fifo_rtl;
reg RST;
reg WRCLK, RDCLK;
localparam CLK100M = 10;
localparam CLK200M = 5;
// Clock
always begin
#(CLK100M/2) WRCLK <= ~WRCLK;
end
always begin
#(CLK200M/2) RDCLK <= ~RDCLK;
end
initial begin
#0;
RST = 1;
WRCLK = 0;
RDCLK = 0;
#100;
RST = 0;
end
reg WREN;
wire AFULL, FULL;
reg [63:0] DIN;
reg RDEN;
wire AEMPTY, EMPTY;
wire [63:0] DOUT;
integer i;
initial begin
#0;
WREN = 0;
RDEN = 0;
wait(!RST);
@(posedge WRCLK);
for(i=0;i<512;i=i+1) begin
WREN = 1;
DIN = 64'hFEDCBA98_76543210 + i;
@(posedge WRCLK);
end
WREN = 0;
DIN = 64'd0;
@(posedge WRCLK);
end
sample_fifo_rtl
#(
.FIFO_DEPTH ( 9 ),
.FIFO_WIDTH ( 65 )
)
u_sample_fifo_rtl
(
.RST_N ( ~RST ),
.FIFO_WR_CLK ( WRCLK ),
.FIFO_WR_ENA ( WREN ),
.FIFO_WR_DATA ( DIN ),
.FIFO_WR_LAST ( 1'b1 ),
.FIFO_WR_FULL ( FULL ),
.FIFO_WR_ALM_FULL ( AFULL ),
.FIFO_WR_ALM_COUNT ( 13'd128 ),
.FIFO_RD_CLK ( RDCLK ),
.FIFO_RD_ENA ( RDEN ),
.FIFO_RD_DATA ( DOUT ),
.FIFO_RD_EMPTY ( EMPTY ),
.FIFO_RD_ALM_EMPTY ( AEMPTY ),
.FIFO_RD_ALM_COUNT ( 13'd256 )
);
endmodule
このRTLは自作FIFOです。
/*
* Copyright (C)2007-2019 AQUAXIS TECHNOLOGY.
* Don't remove this header.
* When you use this source, there is a need to inherit this header.
*
* License: MIT License
*
* For further information please contact.
* URI: http://www.aquaxis.com/
* E-Mail: info(at)aquaxis.com
*/
`timescale 1ps / 1ps
module sample_fifo_rtl
#(
parameter FIFO_DEPTH = 10,
parameter FIFO_WIDTH = 64
)
(
input RST_N,
input FIFO_WR_CLK,
input FIFO_WR_ENA,
input [FIFO_WIDTH -1:0] FIFO_WR_DATA,
input FIFO_WR_LAST,
output FIFO_WR_FULL,
output FIFO_WR_ALM_FULL,
input [FIFO_DEPTH -1:0] FIFO_WR_ALM_COUNT,
input FIFO_RD_CLK,
input FIFO_RD_ENA,
output [FIFO_WIDTH -1:0] FIFO_RD_DATA,
output FIFO_RD_EMPTY,
output FIFO_RD_ALM_EMPTY,
input [FIFO_DEPTH -1:0] FIFO_RD_ALM_COUNT
);
wire wr_ena, wr_full;
reg wr_ena_req_pre, wr_ena_req;
reg wr_rd_ena;
reg [2:0] wr_rd_ena_d;
wire wr_rd_ena_ack;
reg wr_rd_empty;
reg [FIFO_DEPTH -1:0] wr_adrs;
reg [FIFO_DEPTH :0] wr_count, wr_alm_count, wr_count_req_pre, wr_count_req, wr_rd_count;
wire rd_ena, rd_empty;
reg rd_ena_d;
reg rd_ena_req_pre, rd_ena_req;
reg rd_wr_ena;
reg [2:0] rd_wr_ena_d;
wire rd_wr_ena_ack;
reg rd_wr_full;
reg [FIFO_DEPTH -1:0] rd_adrs;
reg [FIFO_DEPTH :0] rd_count, rd_alm_count, rd_count_req_pre, rd_count_req, rd_wr_count;
wire rsv_ena;
reg rsv_empty;
reg [FIFO_WIDTH -1:0] rsv_data;
wire [FIFO_WIDTH -1:0] rd_fifo;
/////////////////////////////////////////////////////////////////////
// Write Block
assign wr_full = wr_count[FIFO_DEPTH];
assign wr_ena = (!wr_full)?(FIFO_WR_ENA):1'b0;
// Write Address
always @(posedge FIFO_WR_CLK or negedge RST_N) begin
if(!RST_N) begin
wr_adrs <= 0;
end else begin
if(wr_ena) wr_adrs <= wr_adrs + 1;
end
end
// make a full and almost full signal
always @(posedge FIFO_WR_CLK or negedge RST_N) begin
if(!RST_N) begin
wr_count <= 0;
wr_alm_count <= 0;
end else begin
if(wr_ena) begin
if(wr_rd_ena) begin
wr_count <= wr_count - {1'b0, wr_rd_count} + 1;
end else begin
wr_count <= wr_count + 1;
end
end else if(wr_rd_ena) begin
wr_count <= wr_count - {1'b0, wr_rd_count};
end
wr_alm_count <= wr_count + {1'b0, FIFO_WR_ALM_COUNT};
end
end
// Read Control signal from Read Block
always @(posedge FIFO_WR_CLK or negedge RST_N) begin
if(!RST_N) begin
wr_rd_count <= {FIFO_DEPTH{1'b0}};
wr_rd_ena_d[2:0] <= 3'd0;
wr_rd_empty <= 1'b0;
wr_rd_ena <= 1'b0;
end else begin
wr_rd_ena_d[2:0] <= {wr_rd_ena_d[1:0], rd_ena_req};
if(wr_rd_ena_d[2:1] == 2'b01) begin
wr_rd_ena <= 1'b1;
wr_rd_count <= rd_count_req;
wr_rd_empty <= rd_empty;
end else begin
wr_rd_ena <= 1'b0;
end
end
end
assign wr_rd_ena_ack = wr_rd_ena_d[2] & wr_rd_ena_d[1];
// Send a write enable signal for Read Block
reg [2:0] wr_rd_ack_d;
always @(posedge FIFO_WR_CLK or negedge RST_N) begin
if(!RST_N) begin
wr_ena_req_pre <= 1'b0;
wr_ena_req <= 1'b0;
wr_count_req_pre <= 0;
wr_count_req <= 0;
wr_rd_ack_d <= 3'd0;
end else begin
wr_rd_ack_d[2:0] <= {wr_rd_ack_d[1:0], rd_wr_ena_ack};
if(wr_ena & FIFO_WR_LAST) begin
wr_ena_req_pre <= 1'b1;
end else if(~wr_ena_req & (wr_rd_ack_d[2:1] == 2'b00)) begin
wr_ena_req_pre <= 1'b0;
end
if(~wr_ena_req & wr_ena_req_pre & (wr_rd_ack_d[2:1] == 2'b00)) begin
if(wr_ena) begin
wr_count_req_pre <= 1;
end else begin
wr_count_req_pre <= 0;
end
end else if(wr_ena) begin
wr_count_req_pre <= wr_count_req_pre + 1;
end
if(~wr_ena_req & wr_ena_req_pre & (wr_rd_ack_d[2:1] == 2'b00)) begin
wr_ena_req <= 1'b1;
wr_count_req <= wr_count_req_pre;
end else if(wr_rd_ack_d[2:1] == 2'b01) begin
wr_ena_req <= 1'b0;
end
end
end
/////////////////////////////////////////////////////////////////////
// Read Block
assign rd_empty = (rd_count == 0)?1'b1:1'b0;
assign rsv_ena = rsv_empty & ~rd_empty;
assign rd_ena = rsv_ena | (FIFO_RD_ENA & ~rd_empty);
// Read Address
always @(posedge FIFO_RD_CLK or negedge RST_N) begin
if(!RST_N) begin
rd_adrs <= 0;
end else begin
if(rd_ena) begin
rd_adrs <= rd_adrs + 1;
end
end
end
// make a empty and almost empty signal
always @(posedge FIFO_RD_CLK or negedge RST_N) begin
if(!RST_N) begin
rd_count <= 0;
rd_alm_count <= 0;
end else begin
if(rd_ena) begin
if(rd_wr_ena) begin
rd_count <= rd_count + {1'b0, rd_wr_count} - 1;
end else begin
rd_count <= rd_count - 1;
end
end else if(rd_wr_ena) begin
rd_count <= rd_count + {1'b0, rd_wr_count};
end
rd_alm_count <= rd_count - {1'b0, FIFO_RD_ALM_COUNT};
end
end
// Write Control signal from Write Block
always @(posedge FIFO_RD_CLK or negedge RST_N) begin
if(!RST_N) begin
rd_wr_ena_d[2:0] <= 3'd0;
rd_wr_count <= {FIFO_DEPTH{1'b0}};
rd_wr_full <= 1'b0;
rd_wr_ena <= 1'b0;
end else begin
rd_wr_ena_d[2:0] <= {rd_wr_ena_d[1:0], wr_ena_req};
if(rd_wr_ena_d[2:1] == 2'b01) begin
rd_wr_ena <= 1'b1;
rd_wr_count <= wr_count_req;
rd_wr_full <= wr_count[FIFO_DEPTH];
end else begin
rd_wr_ena <= 1'b0;
end
end
end
// Write enable signal from write block
assign rd_wr_ena_ack = rd_wr_ena_d[2] & rd_wr_ena_d[1];
// Send a read enable signal for Write Block
reg [2:0] rd_wr_ack_d;
always @(posedge FIFO_RD_CLK or negedge RST_N) begin
if(!RST_N) begin
rd_ena_req_pre <= 1'b0;
rd_ena_req <= 1'b0;
rd_count_req <= {FIFO_DEPTH{1'b0}};
rd_count_req_pre <= {FIFO_DEPTH{1'b0}};
rd_wr_ack_d[2:0] <= 3'd0;
end else begin
rd_wr_ack_d[2:0] <= {rd_wr_ack_d[1:0], wr_rd_ena_ack};
if(rd_ena) begin
rd_ena_req_pre <= 1'b1;
end else if(~rd_ena_req & (rd_wr_ack_d[2:1] == 2'd00)) begin
rd_ena_req_pre <= 1'b0;
end
if(~rd_ena_req & rd_ena_req_pre & (rd_wr_ack_d[2:1] == 2'd00)) begin
if(rd_ena) begin
rd_count_req_pre <= 1;
end else begin
rd_count_req_pre <= 0;
end
end else if(rd_ena) begin
rd_count_req_pre <= rd_count_req_pre + 1;
end
if(~rd_ena_req & rd_ena_req_pre & (rd_wr_ack_d[2:1] == 2'd00)) begin
rd_ena_req <= 1'b1;
rd_count_req <= rd_count_req_pre;
end else if(rd_wr_ack_d[2:1] == 2'b01) begin
rd_ena_req <= 1'b0;
end
end
end
/////////////////////////////////////////////////////////////////////
// rsv Block
always @(posedge FIFO_RD_CLK or negedge RST_N) begin
if(!RST_N) begin
rsv_data <= {FIFO_WIDTH{1'b0}};
rsv_empty <= 1'b1;
end else begin
rd_ena_d <= FIFO_RD_ENA;
if(rd_ena | rd_ena_d) begin
rsv_data <= rd_fifo;
end
if(FIFO_RD_ENA & rd_empty) begin
rsv_empty <= 1'b1;
end else if(rd_ena) begin
rsv_empty <= 1'b0;
end
end
end
assign rsv_alm_empty = (rd_empty & ~rsv_empty);
/////////////////////////////////////////////////////////////////////
// output signals
assign FIFO_WR_FULL = wr_count[FIFO_DEPTH];
assign FIFO_WR_ALM_FULL = wr_alm_count[FIFO_DEPTH];
assign FIFO_RD_EMPTY = rsv_empty;
assign FIFO_RD_ALM_EMPTY = rd_alm_count[FIFO_DEPTH];
assign FIFO_RD_DATA = (rd_ena_d)?rd_fifo:rsv_data;
/////////////////////////////////////////////////////////////////////
// RAM
aq_axi_sdma64_fifo_ram
#(
.DEPTH( FIFO_DEPTH ),
.WIDTH( FIFO_WIDTH )
)
u_aq_axi_sdma64_fifo_ram
(
.WR_CLK ( FIFO_WR_CLK ),
.WR_ENA ( wr_ena ),
.WR_ADRS ( wr_adrs ),
.WR_DATA ( FIFO_WR_DATA ),
.RD_CLK ( FIFO_RD_CLK ),
.RD_ADRS ( rd_adrs ),
.RD_DATA ( rd_fifo )
);
endmodule
module aq_axi_sdma64_fifo_ram
#(
parameter DEPTH = 12,
parameter WIDTH = 32
)
(
input WR_CLK,
input WR_ENA,
input [DEPTH -1:0] WR_ADRS,
input [WIDTH -1:0] WR_DATA,
input RD_CLK,
input [DEPTH -1:0] RD_ADRS,
output [WIDTH -1:0] RD_DATA
);
reg [WIDTH -1:0] ram [0:(2**DEPTH) -1];
reg [WIDTH -1:0] rd_reg;
always @(posedge WR_CLK) begin
if(WR_ENA) ram[WR_ADRS] <= WR_DATA;
end
always @(posedge RD_CLK) begin
rd_reg <= ram[RD_ADRS];
end
assign RD_DATA = rd_reg;
endmodule
あ、できたんですね。
FIFO36E2のテストベンチです。
`timescale 1ns / 1ps
module tb_sample_fifo;
reg RST;
reg WRCLK, RDCLK;
localparam CLK100M = 10;
localparam CLK200M = 5;
// Clock
always begin
#(CLK100M/2) WRCLK <= ~WRCLK;
end
always begin
#(CLK200M/2) RDCLK <= ~RDCLK;
end
initial begin
#0;
RST = 1;
WRCLK = 0;
RDCLK = 0;
#100;
RST = 0;
end
reg SLEEP;
wire WRRSTBUSY, RDRSTBUSY;
reg WREN;
wire [13:0] WRCOUNT;
wire PROGFULL, FULL;
reg [63:0] DIN;
reg RDEN;
wire [13:0] RDCOUNT;
wire PROGEMPTY, EMPTY;
wire [63:0] DOUT;
integer i;
initial begin
#0;
SLEEP = 0;
WREN = 0;
RDEN = 0;
wait(!RST);
wait(!RDRSTBUSY);
wait(!WRRSTBUSY);
@(posedge WRCLK);
for(i=0;i<512;i=i+1) begin
WREN = 1;
DIN = 64'hFEDCBA98_76543210 + i;
@(posedge WRCLK);
end
WREN = 0;
DIN = 64'd0;
@(posedge WRCLK);
end
FIFO36E2
#(
.PROG_EMPTY_THRESH ( 13'd128 ),
.PROG_FULL_THRESH ( 13'd256 ),
.WRITE_WIDTH (72),
.READ_WIDTH (72),
.REGISTER_MODE ("UNREGISTERED"),
.CLOCK_DOMAINS ("INDEPENDENT"),
.FIRST_WORD_FALL_THROUGH ("TRUE"),
.INIT (72'd0),
.SRVAL (72'd0),
.WRCOUNT_TYPE ("SIMPLE_DATACOUNT"),
.RDCOUNT_TYPE ("SIMPLE_DATACOUNT"),
.RSTREG_PRIORITY ("RSTREG"),
.CASCADE_ORDER ("NONE")
)
u_FIFO(
.RST ( RST ),
// Control
.SLEEP ( SLEEP ),
.RDRSTBUSY ( RDRSTBUSY ),
.WRRSTBUSY ( WRRSTBUSY ),
// Write
.WRCLK ( WRCLK ),
.WREN ( WREN ),
.WRERR (),
.WRCOUNT ( WRCOUNT[13:0] ),
.PROGFULL ( PROGFULL ),
.FULL ( FULL ),
.DIN ( DIN[63:0] ),
.DINP ( 8'h00 ),
// Read
.RDCLK ( RDCLK ),
.RDEN ( RDEN ),
.RDCOUNT ( RDCOUNT ),
.RDERR (),
.EMPTY ( EMPTY ),
.PROGEMPTY ( PROGEMPTY ),
.DOUT ( DOUT[63:0] ),
.DOUTP (),
.REGCE ( 1'b1 ),
.RSTREG ( RST ),
// Cascade
.CASDIN (),
.CASDINP (),
.CASDOUT (),
.CASDOUTP (),
.CASPRVEMPTY (),
.CASPRVRDEN (),
.CASNXTRDEN (),
.CASNXTEMPTY (),
.CASOREGIMUX (),
.CASOREGIMUXEN (),
.CASDOMUX (),
.CASDOMUXEN ()
);
endmodule