关于FPGA的memory数据类型reg[15:0] a[2047:0]综合生成lut还是block ram/ m9k的问题

关于FPGA的memory数据reg[15:0] a[2047:0]综合生成lut还是m9k的问题

使用FPGA来综合较大深度的(>1000)ram时需要特别注意其行为描述的语法,因为一旦使用不当,就会造成消耗资源严重超标,从而不满足设计要求。

首先,FPGA内部的ram主要是两种,一种是分布式ram,即lut和周围的DFF,另一种是专用集成块储存器(vivado叫block ram, quartus ii叫 M9K,M144K等)。

分布式ram的常见用法就是用reg定义的小量寄存器数据如 reg [7:0] a(这里仅仅讨论边沿赋值情况,不考虑电平方式的组合逻辑);集成块储存器一般就是IP管理器里面分配的RAM、ROM。

这两者在行为上最大的区别就是允许的并行读写数。基于reg的lutram 只允许在一个always块内赋值,即只能在一个always内的‘ <= ’左边,但允许同时被多个(>=3)always块读取;基于M9K等专用资源的ram最多允许两套读写异步操作,也即是允许在两个并行的always块同时读,两个并行的always块同时写。

基本情况介绍清楚了,有一种情况是,我们可以通过reg数组直接定义一个m9k的集成块ram或者rom 例如 reg[15:0] a[2047:0], 这种深度大的数组,我们期望将其定义为m9k/block ram,而非是lutram,否则要消耗掉超过10k的lut4,那么我们应该注意什么才能让软件正常综合布线?

当然最不会出错的方式是IP管理器生成,这是万无一失的,但是这种方式引入的IP和平台有关,例如从quartus的IP换到vivado平台后是不支持的,即使是同在xilinx的器件,软件版本不同也可能会导致ram ip出现异常,通用性差。

所以,有必要了解 reg[15:0] a[2047:0] 这种方式定义的ram或者rom综合方式。那么是怎么综合的呢?

情形一:

reg signed	 [15:0]  mem16_s3s7[2047:0] ;	//所需ram  
reg [14:0]  cnt_s3s7;						//地址
wire[3:0] pulse1_out;

always@(posedge clk50M)
	if(state1==S3 || state1==S7)
		cnt_s3s7 <= cnt_s3s7 +1'b1;
	else
		cnt_s3s7 <= 15'd0;
		
always@(posedge clk50M)
	if((state1==S3 || state1==S7) && cnt_s3s7 <= 2047 ) begin
	
		if(mem16_s3s7[cnt_s3s7[10:0]] >= 16'd50 )
			pulse1_out[0] <= 1'b1;
		else
			pulse1_out[0] <= 1'b0;
			
		if(mem16_s3s7[cnt_s3s7[10:0]] >= 16'd100 )
			pulse1_out[1] <= 1'b1;
		else
			pulse1_out[1] <= 1'b0;		
			
		if(mem16_s3s7[cnt_s3s7[10:0]] >= 16'd150 )
			pulse1_out[2] <= 1'b1;
		else
			pulse1_out[2] <= 1'b0;	
//			
//		if(mem16_s3s7[cnt_s3s7[10:0]] >= 16'd150 )
//			pulse1_out[3] <= 1'b1;
//		else
//			pulse1_out[3] <= 1'b0;				
//			
	end	
	else
			//do nothing,let pulse keep the last state to reduce edge loss
		;

结果:
在这里插入图片描述

情形二:

reg signed	 [15:0]  mem16_s3s7[2047:0] ;	//所需ram  
reg [14:0]  cnt_s3s7;						//地址
wire[3:0] pulse1_out;

always@(posedge clk50M)
	if(state1==S3 || state1==S7)
		cnt_s3s7 <= cnt_s3s7 +1'b1;
	else
		cnt_s3s7 <= 15'd0;
		
always@(posedge clk50M)
	if((state1==S3 || state1==S7) && cnt_s3s7 <= 2047 ) begin
	
		if(mem16_s3s7[cnt_s3s7[10:0]] >= 16'd50 )
			pulse1_out[0] <= 1'b1;
		else
			pulse1_out[0] <= 1'b0;
			
		if(mem16_s3s7[cnt_s3s7[10:0]] >= 16'd100 )
			pulse1_out[1] <= 1'b1;
		else
			pulse1_out[1] <= 1'b0;		
			
//		if(mem16_s3s7[cnt_s3s7[10:0]] >= 16'd150 )
//			pulse1_out[2] <= 1'b1;
//		else
//			pulse1_out[2] <= 1'b0;	
//			
//		if(mem16_s3s7[cnt_s3s7[10:0]] >= 16'd150 )
//			pulse1_out[3] <= 1'b1;
//		else
//			pulse1_out[3] <= 1'b0;				
//			
	end	
	else
			//do nothing,let pulse keep the last state to reduce edge loss
		;

结果:

上述情形一中的代码生成的就是lutram,最终占用lut超过20000;而二则是集成块,占用的lut则极少。最大的区别在于一中使用了3个if else来读取 mem16_s3s7的数据,尽管每次都是访问同一个地址的值,也被编译器理解为同时3次ram访问;而情形二而则只有2个if else,最后则可以生成m9k。可以进一步验证,4个5个if else 时生成lutram,而1个if else时同2个一样,也是block ram。

所以关键是,描述一个深度大的reg数组时,其操作行为是多少个并行的读写操作,不超过2读2写就能生成block ram,超过就只能是lutram。

如果既要block ram又要同时有超过2次的读取呢?那就得用寄存器做缓冲,打一拍,然后对寄存器进行同时多次的读操作:

reg [14:0]  cnt_s3s7;
reg signed [15:0]	pulsevalue;
wire[3:0] pulse1_out;
always@(posedge clk50M)
	if(state1==S3 || state1==S7)
		cnt_s3s7 <= cnt_s3s7 +1'b1;
	else
		cnt_s3s7 <= 15'd0;
		
always@(posedge clk50M)
	if((state1==S3 || state1==S7) && cnt_s3s7 <= 2047 ) begin
	
		pulsevalue <= mem16_s3s7[ cnt_s3s7[10:0] ];
		
		if(pulsevalue >= lev0 )
			pulse1_out[0] <= 1'b1;
		else
			pulse1_out[0] <= 1'b0;
			
		if(pulsevalue >= lev1 )
			pulse1_out[1] <= 1'b1;
		else
			pulse1_out[1] <= 1'b0;		
			
		if(pulsevalue >= lev2 )
			pulse1_out[2] <= 1'b1;
		else
			pulse1_out[2] <= 1'b0;	
			
		if(pulsevalue >= lev3 )
			pulse1_out[3] <= 1'b1;
		else
			pulse1_out[3] <= 1'b0;				
		
		if(pulsevalue >= lev4 )
			pulse1_out[4] <= 1'b1;
		else
			pulse1_out[4] <= 1'b0;		
			
	end	
	else
			//do nothing,let pulse keep the last state to reduce edge loss
		;

如果要同时3次写操作呢?对不起做不到,block ram允许两次,lutram只允许一次。

  • 15
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值