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;下面一起来编写这个接口吧。 步骤 在…

mysql-bin日志清理,并设置expire_logs_days时间,mysql占用空间过大问题

mysql-bin日志清理&#xff0c;并设置expire_logs_days时间&#xff0c;mysql占用空间过大问题 文章目录 问题查看mysql配置参数解决全局修改参数清理日志规则手动清理my.cnf 外传 问题 最近发现生产环境的服务器磁盘空间吃紧&#xff0c;查下到底是哪里占用的空间比较大&…

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

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

Tomcat Notes: URL Mapping

This is a personal study notes of Apache Tomcat. Below are main reference material. - YouTube Apache Tomcat Full Tutorial&#xff0c;owed by Alpha Brains Courses. https://www.youtube.com/watch?vrElJIPRw5iM&t801s 1、URL Mapping To Resources1.1、What w…

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

随着科技的迅速发展&#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操作完成才能进入插入数据。此时就出现了锁表…

Pandas实战100例 | 案例 14: 数据透视表 - 使用 `pivot_table`

案例 14: 数据透视表 - 使用 pivot_table 知识点讲解 数据透视表是一种常见的数据汇总工具&#xff0c;用于按照一个或多个键对数据进行分类汇总。Pandas 的 pivot_table 函数提供了一种快速创建数据透视表的方法。你可以指定行索引、列索引&#xff0c;以及用于聚合的数据和…

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、首先去…

Windows平台程序和Android平台程序的差异

Windows平台程序和Android平台程序的差异 1 Windows平台环境和Android平台JVM虚拟机的差异&#xff1a; 1&#xff09;由于JVM虚拟机上的数据是大端处理的&#xff0c;而Windows平台上的数据是小端的&#xff0c;所以在一些数据的处理上需要进行转换&#xff1b; 2&#xf…

vmware创建嵌套虚拟机

嵌套虚拟机的搭建 在vmware 虚拟机设置中&#xff0c;打开处理器的虚拟化Intel VT-x/EPT 或AMD-V/RVI&#xff08;v&#xff09;配置虚拟机yum 源&#xff0c;安装qemu、qemu-kvm、libvirt从阿里镜像源下载centos iso 阿里源 centos-7-x86准备虚拟机创建所需xml&#xff0c;ce…

Day32 贪心算法 part02 122. 买卖股票的最佳时机 II 55. 跳跃游戏 45. 跳跃游戏 II

贪心算法 part02 122. 买卖股票的最佳时机 II 55. 跳跃游戏 45. 跳跃游戏 II 122. 买卖股票的最佳时机 II 思路&#xff1a;计算每天的利润&#xff0c;利润如果为正&#xff0c;加到结果中去 class Solution { private:int result 0; public:int maxProfit(vector<int&g…

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

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

完成源示例

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

java常见面试题:如何使用Java进行单元测试?

单元测试是软件开发中的一个重要环节&#xff0c;它确保每个单独的代码单元都能按照预期工作。以下是如何使用Java进行单元测试的详细说明&#xff1a; JUnit&#xff1a; JUnit是Java中最流行的单元测试框架。首先&#xff0c;添加JUnit依赖到你的项目中。如果你使用Maven&…

技术学习周刊第 2 期

有关 TLS/SSL 证书的一切 HTTPS 隐私安全的一些实践 关于 TLS 两篇非常好的文章&#xff0c;如果对 TLS 了解不多的话看上面两篇本章就够了。 从传统的 HTTPS 加密通信&#xff0c;到云原生架构下零信任网络所要求的 mTLS 双向认证&#xff0c;TLS 协议已经是服务通信的必备…

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

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

天梯赛 L1-094 剪切粘贴

原题链接 https://pintia.cn/problem-sets/994805046380707840/exam/problems/1649748772841508869?type7&page0 题面 &#xff08;建议点击原题链接查看&#xff0c;复制过来比较乱&#xff0c;只作预览&#xff09; 使用计算机进行文本编辑时常见的功能是剪切功能&am…

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

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