构建可变变量的存储方式

简介

在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
相关推荐
DS小龙哥10 小时前
基于Zynq FPGA的雷龙SD NAND存储芯片性能测试
fpga开发·sd nand·雷龙·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
上理考研周导师19 小时前
第二章 虚拟仪器及其构成原理
fpga开发
FPGA技术实战21 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
bigbig猩猩1 天前
FPGA(现场可编程门阵列)的时序分析
fpga开发
Terasic友晶科技2 天前
第2篇 使用Intel FPGA Monitor Program创建基于ARM处理器的汇编或C语言工程<二>
fpga开发·汇编语言和c语言
码农阿豪2 天前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发·sd nand·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
江山如画,佳人北望2 天前
EDA技术简介
fpga开发
淘晶驰AK2 天前
电子设计竞赛准备经历分享
嵌入式硬件·fpga开发
最好有梦想~2 天前
FPGA时序分析和约束学习笔记(4、IO传输模型)
笔记·学习·fpga开发