构建可变变量的存储方式

简介

在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
相关推荐
redcocal7 分钟前
地平线内推码 kbrfck
c++·嵌入式硬件·mcu·算法·fpga开发·求职招聘
邹莉斯1 天前
FPGA基本结构和简单原理
fpga开发·硬件工程
悲喜自渡7211 天前
易灵思FPGA开发(一)——软件安装
fpga开发
ZxsLoves1 天前
【【通信协议ARP的verilog实现】】
fpga开发
爱奔跑的虎子1 天前
FPGA与Matlab图像处理之伽马校正
图像处理·matlab·fpga开发·fpga·vivado·xilinx
机器未来2 天前
基于FPGA的SD卡的数据读写实现(SD NAND FLASH)
arm开发·嵌入式硬件·fpga开发
贾saisai2 天前
Xilinx系FPGA学习笔记(八)FPGA与红外遥控
笔记·学习·fpga开发
吉孟雷3 天前
ZYNQ FPGA自学笔记
fpga开发·verilog·led·仿真·vivado·zynq
行者..................3 天前
1. ZYNQ 2. MPSOC 3. FPGA 4. IO分配 5. 硬件设计
fpga开发
tsumikistep3 天前
【无标题】Efinity 0基础进行流水灯项目撰写(FPGA)
fpga开发