当前位置:网站首页>03-SDRAM: Write operation (burst)
03-SDRAM: Write operation (burst)
2022-07-31 07:19:00 【Liu Yaner】
SDRAM 数据写操作(page burst)
- state:
- cnt_cmd: 指令执行时长
- cnt_cmd_reset:上一个计数器的清零信号 (依赖计满信号:trp_end、trfc_end、tmrd_end)
- trcd_end、twrite_end、trp_end: 自家延时结束的信号(依赖 状态)
- wr_ack: 写数据期间的状态,整个过程都拉高
- wr_end: 状态终止
- wr_sdram_en:
设计文件
// SDRAM 数据写操作(page burst)
// 1. state:
// 2. cnt_cmd: 指令执行时长
// 3. cnt_cmd_reset:上一个计数器的清零信号 (依赖计满信号:trp_end、trfc_end、tmrd_end)
// 4. trcd_end、twrite_end、trp_end: 自家延时结束的信号(依赖 状态)
// 5. wr_ack: 写数据期间的状态,整个过程都拉高
// 6. wr_end: 状态终止
// 7. wr_sdram_en:
module sdram_write(
input clk,
input rst_n,
input init_end,
input wr_en,
input [23:0] wr_addr,
input [15:0] wr_data,
input [9:0] wr_burst_len,
output wire wr_ack,
output wire wr_end,
output reg [3:0] write_cmd,
output reg [1:0] write_bank,
output reg [12:0] write_addr,
output reg wr_sdram_en,
output wire [15:0] wr_sdram_data
);
//==========================================parameter===========================================================
//状态机
localparam WR_IDLE = 3'b000, //Write operation initial state
WR_ACT = 3'b001, //行激活状态
WR_TRCD = 3'b011, //row activation wait state
WR_WR = 3'b010, //写操作状态
WR_DATA = 3'b100, //Burst write operation status,Write multiple data in bursts,until the burst is terminated
WR_PRE = 3'b101, //预充电状态
WR_TRP = 3'b111, //Precharge state wait state
WR_END = 3'b110; //结束状态
//等待时间参数定义
localparam TRP = 3'd2 , //预充电等待周期
TRCD = 3'd2 ; //激活等待周期
//命令指令参数
localparam NOP = 4'b0111 , //空操作指令
PRECHARGE = 4'b0010 , //预充电指令
ACTIVE = 4'b0011 , //激活指令
WRITE = 4'b0100 , //写指令
BURST_STOP = 4'b0110 ; //Burst termination instruction
// 突发长度——从外部传入
//parameter MAX_WR = 4'd10;
//==========================================reg=================================================================
reg [7:0] state;
reg [7:0] next_state;
reg [9:0] cnt_cmd;//2、9
//==========================================wire=================================================================
wire trcd_end;
wire twrite_end;
wire trp_end;
wire cnt_cmd_reset;
//==========================================assign=================================================================
assign trcd_end = ((state == WR_TRCD) && (cnt_cmd == TRCD -1))?1'd1:1'd0;
assign twrite_end = ((state == WR_DATA) && (cnt_cmd == wr_burst_len -1))?1'd1:1'd0;
assign trp_end = ((state == WR_TRP) && (cnt_cmd == TRP -1))?1'd1:1'd0;
assign cnt_cmd_reset = ((state == WR_IDLE)||(state == WR_WR) || (state == WR_END) || trcd_end || twrite_end || trp_end)?1'd1:1'd0;
assign wr_ack = ((state == WR_WR) || (state == WR_DATA) && (cnt_cmd <= wr_burst_len -2'd2))?1'd1:1'd0;//在数据低8位末拉低,计数器要在一个完整时钟周期才有效,因此这里是在低8位
assign wr_end = ((state == WR_END)) ? 1'd1 : 1'd0;
assign wr_sdram_data = (wr_sdram_en) ? wr_data : 16'd0;
//==========================================always=================================================================
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
wr_sdram_en <= 1'd0;
end
else
wr_sdram_en <= wr_ack;
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
cnt_cmd <= 10'd0;
end
else if(cnt_cmd_reset)begin
cnt_cmd <= 10'd0;
end
else
cnt_cmd <= cnt_cmd + 10'd1;
end
//==========================================状态机=================================================================
// 第一段
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
state <= WR_IDLE;
end
else
state <= next_state;
end
//第二段
[email protected](*)begin
case(state)
WR_IDLE:
if(init_end && wr_en)
next_state = WR_ACT;
else
next_state = WR_IDLE;
WR_ACT :next_state = WR_TRCD;
WR_TRCD :
if(trcd_end)
next_state = WR_WR;
else
next_state = WR_TRCD;
WR_WR :next_state = WR_DATA;
WR_DATA:
if(twrite_end)
next_state = WR_PRE;
else
next_state = WR_DATA;
WR_PRE :next_state = WR_TRP;
WR_TRP :
if(trp_end)
next_state = WR_END;
else
next_state = WR_TRP;
WR_END: next_state = WR_IDLE;
default: next_state = WR_IDLE;
endcase
end
// 第三段
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
write_cmd <= NOP;
write_bank <= 2'b11;
write_addr <= 13'h1fff;
end
else
case(state)
WR_IDLE : begin
write_cmd <= NOP;
write_bank <= 2'b11;
write_addr <= 13'h1fff;
end
WR_ACT : begin
write_cmd <= ACTIVE;
write_bank <= wr_addr[23:22];//wr_addr有3个地址,bank+13位行地址+9位列地址
write_addr <= wr_addr[21:9];
end
WR_TRCD : begin
write_cmd <= NOP;
write_bank <= 2'b11;
write_addr <= 13'h1fff;
end
WR_WR : begin
write_cmd <= WRITE;
write_bank <= wr_addr[23:22];//wr_addr有3个地址,bank+13位行地址+9位列地址
write_addr <= {
{
4{
1'b0}},wr_addr[8:0]};
end
WR_DATA : begin
write_bank <= 2'b11;
write_addr <= 13'h1fff;
if(twrite_end)
write_cmd <= BURST_STOP;//写完数据,就停止,然后再预充电
else
write_cmd <= NOP;
end
WR_PRE : begin
write_cmd <= PRECHARGE;
write_bank <= wr_addr[23:22];
write_addr <= 13'h0400;//拉高A10,对所有bank预充电
end
WR_TRP: begin
write_cmd <= NOP;
write_bank <= 2'b11;
write_addr <= 13'h1fff;
end
WR_END: begin
write_cmd <= NOP;
write_bank <= 2'b11;
write_addr <= 13'h1fff;
end
default:begin
write_cmd <= NOP;
write_bank <= 2'b11;
write_addr <= 13'h1fff;
end
endcase
end
endmodule
测试文件
`timescale 1ns/1ns
// Author : EmbedFire
// Create Date : 2019/08/25
// Module Name : tb_sdram_init
// Project Name : uart_sdram
// Target Devices: Altera EP4CE10F17C8N
// Tool Versions : Quartus 13.0
// Description : SDRAMInitialize block simulation
//
// Revision : V1.0
// Additional Comments:
//
// 实验平台: 野火_征途Pro_FPGA开发板
// 公司 : http://www.embedfire.com
// 论坛 : http://www.firebbs.cn
// 淘宝 : https://fire-stm32.taobao.com
module tb_sdram_write();
//********************************************************************//
//****************** Internal Signal and Defparam ********************//
//********************************************************************//
//wire define
//clk_gen
wire clk_50m ; //PLL输出50M时钟
wire clk_100m ; //PLL输出100M时钟
wire clk_100m_shift ; //PLL输出100M时钟,相位偏移-30deg
wire locked ; //PLLClock lock signal
wire rst_n ; //复位信号,低有效
//sdram_init
wire [3:0] init_cmd ; //Initialization phase directive
wire [1:0] init_ba ; //初始化阶段L-Bank地址
wire [12:0] init_addr ; //Initialization phase address bus
wire init_end ; //初始化完成信号
// wire auto_ref_req ;
// wire [3:0] auto_ref_cmd ;
// wire [1:0] auto_ref_bank;
// wire [12:0] auto_ref_addr;
// wire auto_ref_end ;
//sdram
wire [3:0] sdram_cmd ; //SDRAM操作指令
wire [1:0] sdram_bank ; //SDRAM L-Bank地址
wire [12:0] sdram_addr ; //SDRAM地址总线
wire [15:0] sdram_dq;
wire wr_ack;
wire wr_end;
wire wr_sdram_en;
wire [3:0] write_cmd;
wire [1:0] write_bank;
wire [12:0] write_addr;
wire [15:0] wr_sdram_data;
//reg define
reg clk_c1 ; //系统时钟
reg sys_rst_n ; //复位信号
// reg auto_ref_en;
//defparam
//Redefine the relevant parameters in the simulation model
defparam sdram_model_plus_inst.addr_bits = 13; //地址位宽
defparam sdram_model_plus_inst.data_bits = 16; //数据位宽
defparam sdram_model_plus_inst.col_bits = 9; //Column address bit width
defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024; //L-Bank容量
//********************************************************************//
//**************************** Clk And Rst ***************************//
//********************************************************************//
//时钟、复位信号
initial
begin
clk_c1 = 1'b1 ;
sys_rst_n <= 1'b0 ;
#200
sys_rst_n <= 1'b1 ;
end
always #10 clk_c1 = ~clk_c1;
//rst_n:复位信号
assign rst_n = sys_rst_n & locked;
// //atref_en:自动刷新使能
// [email protected](posedge clk_100m or negedge rst_n)begin
// if(rst_n == 1'b0)
// auto_ref_en <= 1'b0;
// else if((init_end == 1'b1) && (auto_ref_req == 1'b1))
// auto_ref_en <= 1'b1;
// else if(auto_ref_end == 1'b1)
// auto_ref_en <= 1'b0;
// end
reg wr_en;
//wr_en:写数据使能
[email protected](posedge clk_100m or negedge rst_n)
if(rst_n == 1'b0)
wr_en <= 1'b0;
else if(wr_end == 1'b1)
wr_en <= 1'b0;
else if(init_end == 1'b1)
wr_en <= 1'b1;
else
wr_en <= wr_en;
reg [15:0] wr_data_in;
//wr_data_in:写数据
[email protected](posedge clk_100m or negedge rst_n)
if(rst_n == 1'b0)
wr_data_in <= 16'd0;
else if(wr_data_in == 16'd10)
wr_data_in <= 16'd0;
else if(wr_ack == 1'b1)
wr_data_in <= wr_data_in + 1'b1;
else
wr_data_in <= wr_data_in;
//sdram_cmd,sdram_ba,sdram_addr
assign sdram_cmd = (init_end == 1'b1) ? write_cmd : init_cmd;
assign sdram_bank = (init_end == 1'b1) ? write_bank : init_ba;
assign sdram_addr = (init_end == 1'b1) ? write_addr : init_addr;
//wr_sdram_data
assign sdram_dq = (wr_sdram_en == 1'b1) ? wr_sdram_data : 16'hz;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------- clk_gen_inst -------------
clk_gen clk_gen_inst (
.inclk0 (clk_c1 ),
.areset (~sys_rst_n ),
.c0 (clk_50m ),
.c1 (clk_100m ),
.c2 (clk_100m_shift ),
.locked (locked )
);
//------------- sdram_init_inst -------------
sdram_initial sdram_initial_inst(
.clk (clk_100m ),
.rst_n (rst_n ),
.init_cmd (init_cmd ),
.init_bank (init_ba ),
.init_addr (init_addr ),
.init_end (init_end )
);
// sdram_auto_ref sdram_auto_ref_inst(
// .clk (clk_100m ),
// .rst_n (rst_n ),
// .init_end (init_end ),
// .auto_ref_en (auto_ref_en),
// .auto_ref_req (auto_ref_req ),
// .auto_ref_cmd (auto_ref_cmd ),
// .auto_ref_bank (auto_ref_bank ),
// .auto_ref_addr (auto_ref_addr ),
// .auto_ref_end (auto_ref_end )
// );
sdram_write sdram_write_inst(
.clk(clk_100m),
.rst_n(rst_n),
.init_end(init_end),
.wr_en(wr_en),
.wr_addr(24'h000_000 ),
.wr_data(wr_data_in),
.wr_burst_len(10'd10 ),
.wr_ack(wr_ack),
.wr_end(wr_end),
.write_cmd(write_cmd),
.write_bank(write_bank),
.write_addr(write_addr),
.wr_sdram_en(wr_sdram_en),
.wr_sdram_data(wr_sdram_data)
);
//-------------sdram_model_plus_inst-------------
sdram_model_plus sdram_model_plus_inst(
.Dq (sdram_dq ),
.Addr (sdram_addr ),
.Ba (sdram_bank ),
.Clk (clk_100m_shift ),
.Cke (1'b1 ),
.Cs_n (sdram_cmd[3] ),
.Ras_n (sdram_cmd[2] ),
.Cas_n (sdram_cmd[1] ),
.We_n (sdram_cmd[0] ),
.Dqm (2'b0 ),
.Debug (1'b1 )
);
//------------------------------------------------
//-- 状态机名称查看器
//------------------------------------------------
reg [79:0] name_state_cur; //每字符8位宽,Take the most here10个字符80位宽
always @(*) begin
case(sdram_write_inst.state)
3'b000: name_state_cur = "WR_IDLE";
3'b001: name_state_cur = "WR_ACT ";
3'b011: name_state_cur = "WR_TRCD ";
3'b010: name_state_cur = "WR_WR ";
3'b100: name_state_cur = "WR_DATA ";
3'b101: name_state_cur = "WR_PRE ";
3'b110: name_state_cur = "WR_END";
3'b111: name_state_cur = "WR_TRP ";
default: name_state_cur = "WR_IDLE";
endcase
end
endmodule
打印信息
边栏推荐
- 《白帽子说Web安全》思维导图
- Redux状态管理
- Obtaining server and client information
- Chapter 17: go back to find the entrance to the specified traverse, "ma bu" or horse stance just look greedy, no back to search traversal, "ma bu" or horse stance just look recursive search NXM board
- Zero-Shot Learning & Domain-aware Visual Bias Eliminating for Generalized Zero-Shot Learning
- Install and use uView
- 接口报错no message avaliable
- 简单谈谈Feign
- LeetCode刷题——摆动序列#376#Medium
- 单点登录 思维导图
猜你喜欢
One of the small practical projects - food alliance ordering system
使用powerDesigner反向工程生成Entity
Analysis of the principle and implementation of waterfall flow layout
Automatic translation software - batch batch automatic translation software recommendation
批量翻译软件免费【2022最新版】
LeetCode:952. 按公因数计算最大组件大小【欧拉筛 + 并查集】
【Go报错】go go.mod file not found in current directory or any parent directory 错误解决
LeetCode brush # 376 # Medium - swing sequence
Some derivation formulas for machine learning backpropagation
Koa框架的基本使用
随机推荐
leetcode 406. Queue Reconstruction by Height 根据身高重建队列(中等)
一文读懂 MongoDB 和 MySQL 的差异
LeetCode brush # 376 # Medium - swing sequence
《白帽子说Web安全》思维导图
Gradle剔除依赖演示
科普 | “大姨太”ETH 和 “小姨太”ETC的爱恨情仇
LeetCode刷题——摆动序列#376#Medium
第十七章:回溯探求指定入口的马步遍历,贪心无回溯探求马步遍历,递归探求nxm棋盘带障碍马步遍历
What is float?What is document flow?Several ways and principles of clearing floats?What is BFC, how to trigger BFC, the role of BFC
文件 - 05 下载文件:根据文件Id下载文件
Dart入门
事务的传播机制
浅析瀑布流布局原理及实现方式
在 ASP.NET Core 应用程序启动时运行代码的 3 种方法
高并发与多线程之间的难点对比(容易混淆)
从入门到一位合格的爬虫师,这几点很重要
How to choose a suitable UI component library in uni-app
拉格朗日插值及其应用
讲解实例+详细介绍@Resource与@Autowired注解的区别(全网最全)
ls的用法