SDRAM小项目——写模块

写模块跟着视频看了一个多星期,一开始始终有点弄不清楚,现在记录一下理解的过程。

阅读文档信息:

首先阅读文档信息,了解SDRAM写过程的状态转换和时序图

SDRAM整体状态流程如图所示:

在SDRAM整体系统中,若要进入写模块,则需要从idle状态首先激活一行(row_acttive),再进入写状态(write),发送precharge命令跳出写状态。

WRITEA 状态不使用,因为当处于 WRITEA 状态时,它会自动的进入到 Precharge 状态。想要继续进行写操作就要先再次激活行,也就是说 WRITEA 比在 WRITE 状态的工作效率要低很多。

SDRAM写模块时序图如图所示:

观察时序图可知,在发送active命令时同时发送A0-A12,BANK信息,其中A0-A12指定了行信息,也就是说在ACT命令(激活状态)下,确定了要写入数据的行(SDRAM的数据是一行一行的写),BANK命令确定了要写入数据的SDRAM的块。也就是说在ACT命令下已经确定了bank和row;经过tRCD(至少20ns)时间后,再能发送write命令,发送write命令的同时也发送col命令(col命令也通过A0-A9发送,此时A10为低电平),也同时发送bank命令和数据。设置突发长度为4,等待4个周期的时间写入数据,才可以进行precharge命令退出写模式。

SDRAM写模块状态如图所示(写模块内部状态转移,与SDRAM整体的状态无关):

dle,w_req状态承接上下部分,接收到来自顶层模块的写触发信号(w_trig)后,由idle状态到w_req,此时w_req状态向顶层模块发送req信号,接收到写使能(w_en )信号后进入到act状态,此时也接收到row地址和bank地址信息。由时序图可知经过20ns后进入write状态。在write状态下,当数据写完或者刷新时间到的时候或者指定的行数据写完的时候,需要跳出write状态,此时进入pre状态。在pre状态下,数据写完进入idle状态;当刷新请求来的时候要进行刷新,在顶层模块的设计下刷新结束后会进入仲裁模块,此时需要重新发送写请求,接收到写使能;在指定的一行写完后需要重新激活,此时不需要外部的写使能信号再传输进来。

写模块代码如下:

其中burst_cnt用来计数突发长度,write->pre状态,break_cnt用来计数从pre->act状态(至少20ns)

module sdram_wirte(input					sclk		,input					srst		,//communicate with topinput					w_en		,output	wire			w_req		,output	reg				flag_w_end	,//input					ref_req		,input					w_trig		,//write interfaceoutput	reg	[3:0]		w_cmd		,output	reg	[11:0]		w_addr		,output	wire	[1:0]		bank_addr,output  reg		[15:0]	w_data
);//==========================================================
//=======	define parameter and internal signal	========
//==========================================================
//define state
localparam		s_idle  =  5'b00001;
localparam		s_req	=	5'b00010;
localparam		s_act	=	5'b00100;
localparam		s_wr	= 	5'b01000;
localparam		s_pre	= 	5'b10000;//
localparam		cmd_nop = 5'b0111;
localparam		cmd_pre = 5'b0010;
localparam		cmd_ref = 5'b0001;
localparam		cmd_act = 5'b0011;
localparam		cmd_wr = 5'b0100;reg				flag_wr;
reg[4:0]		state;reg 						flag_act_end;
reg 						flag_pre_end;
reg							sd_row_end;
reg[1:0]					burst_cnt;
reg[1:0]					burst_cnt_t;
reg							wr_data_end;reg[3:0]					act_cnt;
reg[3:0]					break_cnt;
reg[6:0]					col_cnt;reg[11:0]					row_addr;
wire[8:0]					col_addr;//==========================================================
//====================	main	code	====================
//==========================================================
//flag_wr
always@(posedge sclk or negedge srst)beginif(srst == 1'b0)flag_wr <= 1'b0;else if(w_trig == 1'b1  &&flag_wr == 1'b0)flag_wr <= 1'b1;else if(wr_data_end == 1'b1)flag_wr <= 1'b0;
end// w_cmd
always@(posedge sclk or negedge srst)beginif(srst == 1'b0)w_cmd <= cmd_nop;else case(state)s_act:if(act_cnt == 'd0)w_cmd <= cmd_act;elsew_cmd <= cmd_nop;s_wr:if(burst_cnt == 'd0)w_cmd <= cmd_wr;elsew_cmd <= cmd_nop;s_pre:if(break_cnt == 'd0)w_cmd <= cmd_pre;elsew_cmd <= cmd_nop;default:w_cmd <= cmd_nop;endcase
end//burst_cnt
always@(posedge sclk or negedge srst)beginif(srst == 1'b0)burst_cnt  <=  'd0;else if(state == s_wr)burst_cnt <= burst_cnt + 1'b1;elseburst_cnt <= 'd0;
end//burst_cnt
always@(posedge sclk )beginburst_cnt_t <= burst_cnt;
end//state
always@(posedge sclk  or negedge srst)beginif(srst == 1'b0)state  <= s_idle;else case(state)s_idle:if(w_trig == 1'b1)state  <=  s_req;elsestate  <=  s_idle;s_req:if(w_en  ==  1'b1)state  <=  s_act ;elsestate  <=  s_req;s_act:if(flag_act_end  ==  1'b1)state  <=  s_wr;elsestate  <=  s_act;s_wr:if(wr_data_end  ==  1'b1)state  <=  s_pre;else if(ref_req == 1'b1  && burst_cnt_t == 'd3 &&flag_wr  == 1'b1)state  <=  s_pre;else if(sd_row_end == 1'b1  &&  flag_wr == 1'b1)state  <=  s_pre;s_pre:if(ref_req == 1'b1  && flag_wr  ==  1'b1)state  <=  s_req;else if(flag_pre_end  == 1'b1  &&flag_wr == 1'b1)state  <=  s_act;else if(wr_data_end == 1'b1)state  <= s_idle;default:state  <=  s_idle;endcase
end//flag_act_end
always@(posedge sclk or negedge srst)beginif(srst  ==  1'b0)flag_act_end  <=  1'b0;else if (act_cnt  ==  'd3)				//  3?flag_act_end  <=  1'b1;elseflag_act_end  <=  1'b0;
end//flag_pre_end
always@(posedge sclk or negedge srst)beginif(srst  ==  1'b0)flag_pre_end  <=  1'b0;else if (break_cnt  ==  'd3)flag_pre_end  <=  1'b1;elseflag_pre_end  <=  1'b0;
end//break_cnt
always@(posedge sclk or negedge srst)beginif(srst == 1'b0)break_cnt  <=  'd0;else if(state  ==  s_pre)break_cnt <= break_cnt +1'b1;elsebreak_cnt <= 'd0;
endalways@(posedge sclk or negedge srst)beginif(srst == 1'b0)wr_data_end <=  'd0;else if(row_addr == 'd1 && col_addr == 'd511)\wr_data_end  <= 1'b1;elsewr_data_end <= 1'b0;
endalways@(posedge sclk or negedge srst)beginif(srst == 1'b0)col_cnt <= 'd0;else if(col_addr  ==  'd511)col_cnt <= 'd0;else if(burst_cnt_t  == 'd3)col_cnt <= col_cnt + 1'b1;
endalways@(posedge sclk or negedge srst)beginif(srst == 1'b0)row_addr <= 'd0;else if(sd_row_end == 1'b1)row_addr <= row_addr +'b1;
end//w_addr
always@(*)begincase(state)s_act:if(act_cnt == 'd0)w_addr <= row_addr;s_wr:w_addr <= {3'b000,col_addr};s_pre:if(break_cnt == 'd0)w_addr <= {12'b0100_0000_0000};endcase
endalways@(posedge sclk or negedge srst )beginif(srst == 1'b0)sd_row_end <= 1'b0;else if(col_addr == 'd510)sd_row_end <= 1'b1;else	sd_row_end <= 1'b0;
endalways@(posedge sclk or negedge srst )beginif(srst == 1'b0)flag_w_end <= 1'b0;else if((state == s_pre && ref_req == 1'b1)|| (state == s_pre && wr_data_end == 1'b1))flag_w_end <= 1'b1;else	flag_w_end <= 1'b0;
endassign bank_addr = 2'b00;
assign col_addr = {col_cnt,burst_cnt_t};
assign w_req = state[1];//产生测试数据
always@(*)begincase(burst_cnt_t):0: w_data <= 'd3;1: w_data <= 'd5;2: w_data <= 'd7;3: w_data <= 'd9;endcase
endendmodule

顶层模块代码:

在测试中添加了一个w_trig信号

疑问:实际上w_trig信号如何产生?fpga input?按下按键?

module	sdram_top(input			sclk,input			srst,//sdram		interfaceoutput	wire	sdram_clk,output	wire	sdram_cke,output	wire	sdram_cs_n,output	wire	sdram_cas_n,output	wire	sdram_ras_n,output	wire	sdram_we_n,output	wire	[1:0]	sdram_bank,output	reg		[11:0]	sdram_addr,output	wire	[1:0]	sdram_dqm,inout			[15:0]	sdram_dq,//input 			w_trig
);//==========================================================
//=======	define parameter and internal signal	========
//==========================================================//define state machine
reg		[4:0]	state;
localparam		idle		=		5'b00001;
localparam		arbit		= 		5'b00010;
localparam		aref		= 		5'b00100;
localparam		write		=		5'b01000;
localparam		read		=       5'b10000;//init module
reg[3:0]		sd_cmd;
wire 			flag_init_end;
wire	[3:0]	init_cmd;
wire	[11:0]	init_addr;//refresh module
reg				ref_en;
wire			ref_req;
wire			flag_ref_end;
wire 	[3:0]	cmd_reg;
wire	[11:0]	ref_addr;//write modulereg				w_en	;	wire               w_req	;	wire               flag_w_end;wire[3:0]           w_cmd		;wire[11:0]           w_addr		;wire[1:0]           w_bank_addr;wire[15:0]			w_data;//==========================================================
//====================	main	code	====================
//==========================================================
always@(posedge sclk or negedge srst) beginif(srst 	==		1'b0)state	<=		idle;elsecase(state)idle:if(flag_init_end	==	1'b1)state	<=	arbit;elsestate	<=	idle;arbit:if(ref_en	==		1'b1)state	<=	aref;else if(w_en == 1'b1)state <= write;elsestate	<=	arbit;aref:if(flag_ref_end	==	1'b1)state	<=	arbit;elsestate	<=	aref;write:if(flag_w_end == 1'b1)state <= arbit;elsestate <= write;default:	state	<=	idle;endcase
endalways@(*)
begincase(state)idle:beginsd_cmd <= init_cmd;sdram_addr <= init_addr;endaref:beginsd_cmd <= cmd_reg;sdram_addr <= ref_addr;endwrite:beginsd_cmd <= w_cmd;sdram_addr <= w_addr;enddefault:beginsd_cmd <= 4'b0111;//nopsdram_addr <= 'd0;endendcase	
end//ref_en
always@(posedge sclk or  negedge srst)beginif(srst == 1'b0)ref_en <= 1'b0;else if(state == arbit	&& ref_req == 1'b1)ref_en <= 1'b1;else	ref_en <= 1'b0;
end//w_en
always@(posedge sclk or negedge srst)beginif(srst == 1'b0)w_en <= 1'b0;else if(state == arbit && ref_en == 1'b0 && w_req == 1'b1)w_en <= 1'b1;elsew_en <= 1'b0;
endassign	sdram_cke	=	1'b1;
//assign	sdram_addr	=	(state == idle) ?init_addr:ref_addr;
//assign	{sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = (state == idle) ?init_cmd:cmd_reg;
assign	{sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = sd_cmd;
assign 	sdram_dqm	=	2'b00;
assign	sdram_clk	=	~sclk;	//内部时钟上升沿采集命令,命令又是由系统时钟上升沿产生的??(为了保证采样时刻处在数据中间时刻)
assign	sdram_dq = (state == write)?w_data:{16{1'bz}};
assign  sdram_bank = (state == write)?w_bank_addr:2'b00;sdram_init	sdram_init_inst(.sclk				(sclk)	,.srst				(srst)	,.cmd_reg			(init_cmd)	,	.sdram_addr			(init_addr)	,	.flag_init_end	    		(flag_init_end)
);	sdram_aref		sdram_aref(.sclk						(sclk),.srst						(srst),//commmunicate with arbit.ref_en							(ref_en),.ref_req						(ref_req),.flag_ref_end					(flag_ref_end),//others                       .flag_init_end					(flag_init_end),.cmd_reg						(cmd_reg),.ref_addr						(ref_addr)
);sdram_wirte		sdram_wirte_inst(.sclk							(sclk),.srst							(srst),//communicate with top          .w_en							(w_en		),.w_req							(w_req		),.flag_w_end						(flag_w_end),//                              .ref_req						(ref_req),.w_trig							(w_trig	),//write interface               .w_cmd							(w_cmd		),.w_addr							(w_addr		),.bank_addr                      (w_bank_addr  ),.w_data							(w_data)
);endmodule

测试代码:

`timescale	1ns/1nsmodule	tb_sdram_top;reg			sclk;reg			srst;
//----------------------------------------wire	sdram_clk;wire	sdram_cke;wire	sdram_cs_n;wire	sdram_cas_n;wire	sdram_ras_n;wire	sdram_we_n;wire	[1:0]	sdram_bank;wire	[11:0]	sdram_addr;wire	[1:0]	sdram_dqm;wire	[15:0]	sdram_dq;reg				w_trig;
//----------------------------------------initial begin	w_trig <= 0;#205000w_trig <= 'b1;#20w_trig <= 'b0;
endinitial beginsclk <= 1;srst <= 0;#100srst <=1;
endalways	#10		sclk <= ~sclk;defparam sdram_model_plus_inst.addr_bits =    12;
defparam sdram_model_plus_inst.data_bits =    16;
defparam sdram_model_plus_inst.col_bits  =    9;
defparam sdram_model_plus_inst.mem_sizes =    2*1024*1024;//1 M sdram_top		sdram_top_inst(.sclk							(sclk		),.srst							(srst		),.sdram_clk						(sdram_clk	),.sdram_cke						(sdram_cke	),.sdram_cs_n						(sdram_cs_n	),.sdram_cas_n						(sdram_cas_n),.sdram_ras_n						(sdram_ras_n),.sdram_we_n						(sdram_we_n	),.sdram_bank						(sdram_bank	),.sdram_addr						(sdram_addr	),.sdram_dqm						(sdram_dqm	),.sdram_dq						(sdram_dq	),.w_trig							(w_trig)
);sdram_model_plus sdram_model_plus_inst(.Dq				(sdram_dq)	,.Addr				(sdram_addr), .Ba				(sdram_bank), .Clk				(sdram_clk), .Cke				(sdram_cke), .Cs_n				(sdram_cs_n), .Ras_n				(sdram_ras_n), .Cas_n				(sdram_cas_n), .We_n				(sdram_we_n), .Dqm				(sdram_dqm),.Debug				(1'b1));endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/621729.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法小课堂】动态规划

动态规划 动态规划相信大家都知道&#xff0c;动态规划算法也是新手在刚接触算法设计时很苦恼的问题&#xff0c;有时候觉得难以理解&#xff0c;但是真正理解之后&#xff0c;就会觉得动态规划其实并没有想象中那么难。网上也有很多关于讲解动态规划的文章&#xff0c;大多都…

Java--业务场景:在Spring项目启动时加载Java枚举类到Redis中(补充)

文章目录 前言步骤测试结果 前言 通过Java–业务场景&#xff1a;在Spring项目启动时加载Java枚举类到Redis中,我们成功将Java项目里的枚举类加载到Redis中了&#xff0c;接下来我们只需要写接口获取需要的枚举值数据就可以了&#xff0c;下面一起来编写这个接口吧。 步骤 在…

leetcode238:除自身以外数组的乘积

文章目录 1.使用除法&#xff08;违背题意&#xff09;2.左右乘积列表3.空间复杂度为O(1)的方法 在leetcode上刷到了这一题&#xff0c;一开始并没有想到好的解题思路&#xff0c;写篇博客再来梳理一下吧。 题目要求&#xff1a; 不使用除法在O(n)时间复杂度内 1.使用除法&am…

新一代数字原住民:市场痛点与“繁”思维应对之道

随着科技的迅速发展&#xff0c;尤其是互联网的普及&#xff0c;新一代数字原住民经营者已经逐渐成为市场的主力军。不同于传统的消费者&#xff0c;有着独特的消费习惯和心理需求。企业要在这激烈的市场竞争中获得优势&#xff0c;深入了解这一群体的特征和心理、行为&#xf…

有趣的事,讲给有趣的人听

哈哈哈&#xff0c;今天不写技术了&#xff0c;今天分享一下生活&#xff0c;技术我们什么时候都可以学&#xff0c;但是生活更值得我们现在就去更好的体验&#xff01; 两年多的涤生大数据&#xff0c;认识了形形色色的小伙伴&#xff0c;陆续沟通下来6000多人&#xff0c;彼时…

数据库锁表原因、排查、解决

一.场景 场景1场景2二.原因三.排查四.解决方案 一.场景 场景1 锁表通常发生在DML&#xff08; insert 、update 、delete &#xff09; A操作进行全量数据同步&#xff0c;对整个表的粒度进行上锁&#xff0c;导致B操作只能等待A操作完成才能进入插入数据。此时就出现了锁表…

Elasticsearch windows开箱即用【记录】

一、准备工作 安装ES之前要在本机安装好JDK&#xff0c;对应的兼容性见官网链接&#xff1a;https://www.elastic.co/cn/support/matrix ES官网链接&#xff1a;https://www.elastic.co/cn/, 我本机安装的是JDK8&#xff0c;测试使用的是7.3.0版本的ES和Kibana。 1、首先去…

PyTorch项目源码学习(3)——Module类初步学习

torch.nn.Module Module类是用户使用torch来自定义网络模型的基础&#xff0c;Module的设计要求包括低耦合性&#xff0c;高模块化等等。一般来说&#xff0c;计算图上所有的子图都可以是Module的子类&#xff0c;包括卷积&#xff0c;激活函数&#xff0c;损失函数节点以及相…

完成源示例

本主题演示如何创作和使用自己的完成源类&#xff0c;类似于 .NET 的 TaskCompletionSource。 completion_source 示例的源代码 下面的列表中的代码作为示例提供。 其目的是说明如何编写自己的版本。 例如&#xff0c;支持取消和错误传播不在此示例的范围内。 #include <w…

VR全景技术如何应用在城市发展,助力城市宣传展示

引言&#xff1a; 随着科技的不断发展&#xff0c;VR全景技术正逐渐渗透到各行各业&#xff0c;其中较为广泛的应用之一便是城市展示。那么VR全景技术如何运用在城市展示领域&#xff0c;这项技术给城市发展带来了哪些好处&#xff1f; 一. VR全景技术简介 1.什么是VR全景技术…

怎样制作一本旅游电子相册呢?

​随着数码技术的发展&#xff0c;旅游电子相册已成为越来越多旅游爱好者的必备工具。它不仅能让您随时随地欣赏自己的旅行回忆&#xff0c;还能分享给亲朋好友&#xff0c;甚至上传到社交媒体上&#xff0c;让更多人了解您的旅行故事。那么&#xff0c;如何制作一本精美的旅游…

Postman接口测试之断言,全网最细教程没有之一!

一、断言 在 postman 中我们是在Tests标签中编写断言&#xff0c;同时右侧封装了常用的断言&#xff0c;当然 Tests 除了可以作为断言&#xff0c;还可以当做后置处理器来编写一些后置处理代码&#xff0c;经常应用于&#xff1a; 【1】获取当前接口的响应&#xff0c;传递给…

【数据开发】BI数据报表之数据可测试性设计与分析

文章目录 1、什么是BI&数据报表2、什么是可测试性3、数据测试与方法3.1 数据准确性与对比&#xff08;重要&#xff09;3.2 数据安全性 1、什么是BI&数据报表 数据报表是一种数据可视化工具 用于将数据以图表、表格和其他可视化形式呈现出来&#xff0c;以便用户可以…

BRC20通证的深度科普:它的潜力与如何导入到bitget

​BRC-20通证是什么&#xff1f; BRC-20通证&#xff1a;比特币上的“变形金刚”&#xff1f;&#xff01;不依赖智能合约&#xff0c;它们就像拥有超能力的外星人&#xff0c;直接在比特币的最小单位——聪上刻写JSON代码。哈哈&#xff0c;这比把房子建在乐高积木上还要刺激…

逆水行舟 不进则退

目录 一、前言 二、2023年度总结 三、2024展望未来 一、前言 这是我从工作以来到现在最喜欢的一句话&#xff0c;我想把这句话送给自己也想送给大家。 2019年7月实习到现在已经过去了四年多&#xff0c;进入2024年也迎来了我工作生涯的第五个年头。 在这个行业里&#xff…

Docker五部曲之四:Docker Compose

文章目录 前言Compose应用程序模型Compose规范顶层属性servicenetworkvolumesconfigssecrets 环境变量.env文件environment属性主机shell中的环境变量 Profiles&#xff08;剖面&#xff09;启动剖面自动启动剖面和依赖项解析 多compose.yml文件共享与扩展构建规范构建属性 部署…

网站后台拿Webshell

通过注入或者其他途径&#xff0c;获取网站管理员账号和密码后&#xff0c;找到后台登录地址&#xff0c;登录后&#xff0c;寻找后台漏洞上传网页后门&#xff0c;获取网站的webshell webshell的作用是方便攻击者&#xff0c;webshel是拥有fso权限&#xff0c;根据fso权限的不…

论文阅读:Bayesian GAN

Bayesian GAN 点击访问paper 官方github 半监督学习对比算法 1.简介 贝叶斯 GAN&#xff08;Saatchi 和 Wilson&#xff0c;2017&#xff09;是生成对抗网络&#xff08;Goodfellow&#xff0c;2014&#xff09;的贝叶斯公式&#xff0c;我们在其中学习生成器参数 θ g \th…

mybatisplus(service CRUD 接口)

一、我们在控制器层都是调用Service层&#xff0c;不会直接调用仓储层。现在我给大家介绍一下怎么快速实现Service 的CRUD 定义接口&#xff1a;IProductService 继承IService<实体> package com.saas.plusdemo;import com.baomidou.mybatisplus.extension.service.ISe…