简介
在FPGA中最常用的IP核就是FIFO和RAM了,这两个通常由官方IP来实现,但是在IP中,如果想要修改参数就十分困难。因此就需要构建可变存储空间的FIFO和RAM。通常构建FIFO可以用XILINX提供的源语以及宏来实现,构建小容量的RAM可以用LUT来实现。
FIFO
c
`timescale 1ns / 1ps
module xpm_asfifo #(
parameter FIFO_MEMORY_TYPE = "block" , //block distributed
parameter WRITE_DATA_WIDTH = 32 ,
parameter FIFO_WRITE_DEPTH = 2048 ,
parameter WR_DATA_COUNT_WIDTH = 12 ,
parameter READ_MODE = "std" ,//"std" "fwft"
parameter READ_DATA_WIDTH = 32 ,
parameter RD_DATA_COUNT_WIDTH = 12 ,
parameter FIFO_READ_LATENCY = 1
)
(
input rst ,
input wr_clk ,
input rd_clk ,
input [WRITE_DATA_WIDTH-1:0] din ,
input wr_en ,
input rd_en ,
output [READ_DATA_WIDTH-1:0] dout ,
output full ,
output empty ,
output [RD_DATA_COUNT_WIDTH-1:0] rd_data_count ,
output [WR_DATA_COUNT_WIDTH-1:0] wr_data_count
);
wire pre_full ;
wire wr_rst_busy ;
wire [WRITE_DATA_WIDTH-1:0] din_sw ;
wire [READ_DATA_WIDTH-1:0] dout_sw ;
genvar i;
generate
if(WRITE_DATA_WIDTH>=READ_DATA_WIDTH)
for(i = 0; i < WRITE_DATA_WIDTH/READ_DATA_WIDTH; i = i + 1)
begin
assign din_sw[i*READ_DATA_WIDTH+:READ_DATA_WIDTH] = din[WRITE_DATA_WIDTH - READ_DATA_WIDTH - i*READ_DATA_WIDTH+:READ_DATA_WIDTH];
end
else
assign din_sw = din;
endgenerate
genvar j;
generate
if(WRITE_DATA_WIDTH<READ_DATA_WIDTH)
for(j = 0; j < READ_DATA_WIDTH/WRITE_DATA_WIDTH; j = j + 1)
begin
assign dout[j*WRITE_DATA_WIDTH+:WRITE_DATA_WIDTH] = dout_sw[READ_DATA_WIDTH - WRITE_DATA_WIDTH - j*WRITE_DATA_WIDTH+:WRITE_DATA_WIDTH];
end
else
assign dout = dout_sw;
endgenerate
assign full = wr_rst_busy|pre_full;
xpm_fifo_async #(
.CDC_SYNC_STAGES(2), // DECIMAL
.DOUT_RESET_VALUE("0"), // String
.ECC_MODE("no_ecc"), // String
.FIFO_MEMORY_TYPE(FIFO_MEMORY_TYPE), // String
.FIFO_READ_LATENCY(FIFO_READ_LATENCY), // DECIMAL
.FIFO_WRITE_DEPTH(FIFO_WRITE_DEPTH), // DECIMAL
.FULL_RESET_VALUE(0), // DECIMAL
.PROG_EMPTY_THRESH(10), // DECIMAL
.PROG_FULL_THRESH(10), // DECIMAL
.RD_DATA_COUNT_WIDTH(RD_DATA_COUNT_WIDTH), // DECIMAL
.READ_DATA_WIDTH(READ_DATA_WIDTH), // DECIMAL
.READ_MODE(READ_MODE), // String
.RELATED_CLOCKS(0), // DECIMAL
//.SIM_ASSERT_CHK(0), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
.USE_ADV_FEATURES("0707"), // String
.WAKEUP_TIME(0), // DECIMAL
.WRITE_DATA_WIDTH(WRITE_DATA_WIDTH), // DECIMAL
.WR_DATA_COUNT_WIDTH(WR_DATA_COUNT_WIDTH) // DECIMAL
)
xpm_fifo_async_inst (
.almost_empty(), // 1-bit output: Almost Empty : When asserted, this signal indicates that
// only one more read can be performed before the FIFO goes to empty.
.almost_full(), // 1-bit output: Almost Full: When asserted, this signal indicates that
// only one more write can be performed before the FIFO is full.
.data_valid(), // 1-bit output: Read Data Valid: When asserted, this signal indicates
// that valid data is available on the output bus (dout).
.dbiterr(), // 1-bit output: Double Bit Error: Indicates that the ECC decoder detected
// a double-bit error and data in the FIFO core is corrupted.
.dout(dout_sw), // READ_DATA_WIDTH-bit output: Read Data: The output data bus is driven
// when reading the FIFO.
.empty(empty), // 1-bit output: Empty Flag: When asserted, this signal indicates that the
// FIFO is empty. Read requests are ignored when the FIFO is empty,
// initiating a read while empty is not destructive to the FIFO.
.full(pre_full), // 1-bit output: Full Flag: When asserted, this signal indicates that the
// FIFO is full. Write requests are ignored when the FIFO is full,
// initiating a write when the FIFO is full is not destructive to the
// contents of the FIFO.
.overflow(), // 1-bit output: Overflow: This signal indicates that a write request
// (wren) during the prior clock cycle was rejected, because the FIFO is
// full. Overflowing the FIFO is not destructive to the contents of the
// FIFO.
.prog_empty(), // 1-bit output: Programmable Empty: This signal is asserted when the
// number of words in the FIFO is less than or equal to the programmable
// empty threshold value. It is de-asserted when the number of words in
// the FIFO exceeds the programmable empty threshold value.
.prog_full(), // 1-bit output: Programmable Full: This signal is asserted when the
// number of words in the FIFO is greater than or equal to the
// programmable full threshold value. It is de-asserted when the number of
// words in the FIFO is less than the programmable full threshold value.
.rd_data_count(rd_data_count), // RD_DATA_COUNT_WIDTH-bit output: Read Data Count: This bus indicates the
// number of words read from the FIFO.
.rd_rst_busy(), // 1-bit output: Read Reset Busy: Active-High indicator that the FIFO read
// domain is currently in a reset state.
.sbiterr(), // 1-bit output: Single Bit Error: Indicates that the ECC decoder detected
// and fixed a single-bit error.
.underflow(), // 1-bit output: Underflow: Indicates that the read request (rd_en) during
// the previous clock cycle was rejected because the FIFO is empty. Under
// flowing the FIFO is not destructive to the FIFO.
.wr_ack(), // 1-bit output: Write Acknowledge: This signal indicates that a write
// request (wr_en) during the prior clock cycle is succeeded.
.wr_data_count(wr_data_count), // WR_DATA_COUNT_WIDTH-bit output: Write Data Count: This bus indicates
// the number of words written into the FIFO.
.wr_rst_busy(wr_rst_busy), // 1-bit output: Write Reset Busy: Active-High indicator that the FIFO
// write domain is currently in a reset state.
.din(din_sw), // WRITE_DATA_WIDTH-bit input: Write Data: The input data bus used when
// writing the FIFO.
.injectdbiterr(1'b0), // 1-bit input: Double Bit Error Injection: Injects a double bit error if
// the ECC feature is used on block RAMs or UltraRAM macros.
.injectsbiterr(1'b0), // 1-bit input: Single Bit Error Injection: Injects a single bit error if
// the ECC feature is used on block RAMs or UltraRAM macros.
.rd_clk(rd_clk), // 1-bit input: Read clock: Used for read operation. rd_clk must be a free
// running clock.
.rd_en(rd_en), // 1-bit input: Read Enable: If the FIFO is not empty, asserting this
// signal causes data (on dout) to be read from the FIFO. Must be held
// active-low when rd_rst_busy is active high.
.rst(rst), // 1-bit input: Reset: Must be l to wr_clk. The clock(s) can be
// unstable at the time of applying reset, but reset must be released only
// after the clock(s) is/are stable.
.sleep(1'b0), // 1-bit input: Dynamic power saving: If sleep is High, the memory/fifo
// block is in power saving mode.
.wr_clk(wr_clk), // 1-bit input: Write clock: Used for write operation. wr_clk must be a
// free running clock.
.wr_en(wr_en) // 1-bit input: Write Enable: If the FIFO is not full, asserting this
// signal causes data (on din) to be written to the FIFO. Must be held
// active-low when rst or wr_rst_busy is active high.
);
// End of xpm_fifo_async_inst instantiation
endmodule
RAM
带有两个写端口的双端RAM
首先例化一个大的二维数组。端口A和端口B都可写,但只有端口B可读
c
//带有两个写端口的双端块RAM
module tdpram #(
parameter AW = 10, //地址位宽
parameter DW = 8 //数据位宽
)
(
input clka ,
input clkb ,
input wea ,
input web ,
input [AW-1:0] addra ,
input [AW-1:0] addrb ,
input [DW-1:0] dina ,
input [DW-1:0] dinb ,
output reg [DW-1:0] douta ,
output reg [DW-1:0] doutb
);
reg [DW-1:0] ram [(2**AW)-1:0]; //例化存储空间
//初始化存储空间
integer i;
initial for (i=0; i < (2**AW); i=i+1) ram[i] = 0;
//port 1
always@(posedge clka)
if (wea)
ram[addra] <= dina;
always@(posedge clka)
douta <= ram[addra];
//port 2
always@(posedge clkb)
if (web)
ram[addrb] <= dinb;
//端口b可读
always@(posedge clkb)
doutb <= ram[addrb];
endmodule
写优先模式的单端块RAM
和上面的例化一样,但是当有写使能的时候,读数据的端口不刷新,即写数据优先
c
// 写优先模式的单端块RAM,Wrist_first
module spram #(
parameter AW = 10,
parameter DW = 8
)
(
input clka ,
input wea ,
input [AW-1:0] addra ,
input [DW-1:0] dina ,
output reg [DW-1:0] douta
);
reg [DW-1:0] ram [(2**AW)-1:0];
integer i;
initial for (i=0; i < (2**AW); i=i+1) ram[i] = 0;
always @(posedge clka)
if (wea)
begin
ram[addra] <= dina;
douta <= dina;
end
else
douta <= ram[addra];
endmodule
双时钟控制,伪双端块RAM
A时钟写 B时钟读
c
//双时钟控制,伪双端块RAM
module sdpram #(
parameter AW = 10,
parameter DW = 8
)
(
input clka ,
input clkb ,
input wea ,
input [AW-1:0] addra ,
input [AW-1:0] addrb ,
input [DW-1:0] dina ,
output reg [DW-1:0] doutb
);
reg [DW-1:0] ram [(2**AW)-1:0];
integer i;
initial for (i=0; i < (2**AW); i=i+1) ram[i] = 0;
always@(posedge clka)
if (wea)
ram[addra] <= dina;
always@(posedge clkb)
doutb <= ram[addrb];
endmodule