当前位置:网站首页>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
打印信息

边栏推荐
- Explain the example + detail the difference between @Resource and @Autowired annotations (the most complete in the entire network)
- 04-SDRAM:读操作(突发)
- 文本三剑客之e`grep,seq文本编辑工具
- js原型详解
- 文件 - 04 下载文件: 根据文件下载链接下载文件
- Zotero | Zotero translator plugin update | Solve the problem that Baidu academic literature cannot be obtained
- 使用powerDesigner反向工程生成Entity
- Hook API
- 讲解实例+详细介绍@Resource与@Autowired注解的区别(全网最全)
- Project exercise - memorandum (add, delete, modify, check)
猜你喜欢

测试 思维导图

单点登录 思维导图

Zero-Shot Learning & Domain-aware Visual Bias Eliminating for Generalized Zero-Shot Learning

uni-app生命周期

iOS大厂面试查漏补缺

浅析v-model语法糖的实现原理与细节知识及如何让你开发的组件支持v-model

文件 - 04 下载文件: 根据文件下载链接下载文件

Conditional statements of shell (test, if, case)

【Go语言刷题篇】Go完结篇函数、结构体、接口、错误入门学习

One of the small practical projects - food alliance ordering system
随机推荐
DirectExchange交换机简单入门demo
2022.7.29 Array
(border-box)盒子模型w3c、IE的区别
Explain the example + detail the difference between @Resource and @Autowired annotations (the most complete in the entire network)
Kubernetes调度
js原型详解
银河麒麟V10 sp1服务器安装英伟达显卡驱动
多进程全局变量失效、变量共享问题
shell的脚本的基本用法
Moment.js常用方法
事务的传播机制
2. (1) Chained storage of stack, operation of chain stack (illustration, comment, code)
MySQL的触发器
360 push-360 push tool-360 batch push tool
Conditional statements of shell (test, if, case)
LeetCode刷题——摆动序列#376#Medium
04-SDRAM:读操作(突发)
tidyverse笔记——tidyr包
Gradle剔除依赖演示
【云原生】-Docker容器迁移Oracle到MySQL