基于fpga的256m的SDRAM控制器
2018/7/26
受教于邓堪文老师,开始真真学习控制sdram
由于自己买的sdram模块是256的,原来老师的是128,所以边学边改,不知道最后好不好使,但是我有信心
一.sdram的初始化
sdram介绍啥的就不用了,上来就是干,简单粗暴。
1.下面是引脚说明,看不懂自己可以用百度翻译,需要注意的是红框内的地址引脚和行列地址是复用的,A0~A12是行地址,A0~8是列地址
简单说一下SDRAM的容量计算:数据位宽 *行地址*列地址*bank数,我们用的256有4个bank,就是:16*8192*512*4

2.我的fpga是50m时钟,20ns一个周期,下图是初始化的时序图
sdram上电要延时至少100us,我们是延时200us,然后precharge(预充电)命令,隔tRP时间也就是一个时钟周期20ns进行第一次auto_refresh(自刷新),再隔tRC时间也就是四个时钟周期进行第二次auto_refresh命令,
又tRC时间进行mode_register(模式寄存器配置)。期间的NOP是空操作命令。还有就是这几个时间要看自己使用sdram的datasheet

3.上面说的命令也是要去datasheet手册去找,对应CS,RAS,CAS,WE的操作

4.模式配置对应datasheet ,根据红框addr:0_0000_0010_0010

5.再来一张时序图

6.该上源码了,应该没啥看不懂的吧
`timescale 1ns/1ns
module tb_sdram_top;
reg sclk ;
reg s_rst_n ;
//----------------------------------------------------------
wire sdram_clk ;
wire sdram_cke ;
wire sdram_cs_n ;
wire sdram_cas_n ;
wire sdram_ras_n ;
wire sdram_we_n ;
:] sdram_bank ;
:] sdram_addr ;
:] sdram_dqm ;
:] sdram_dq ;
initial begin
sclk = ;
s_rst_n <= ;
#
s_rst_n <= ;
end
sclk = ~sclk;
sdram_top sdram_top_inst(
//system signals
.sclk (sclk ),
.s_rst_n (s_rst_n ),
//SDRAM Interfaces
.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 )
);
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 ('b1 )
);
endmodule
tb_sdram_top
module sdram_ini(
//systejm signal
input sclk ,
input s_rst_n ,
//others
:] cmd_reg ,
:] sdram_addr ,
output flag_ini_end
);
//==============================================================================\
//*********************Define Parameter and Internal Signal ********************
//==============================================================================/
;
//SDRAM Command
'b0111 ;
'b0010 ;
'b0001 ;
'b0000 ;
:] cnt_200us ;
wire flag_200us ;
:] cnt_cmd ;
//=============================================================================\
//********************** Main Code ***************************************
//=============================================================================/
always @(posedge sclk or negedge s_rst_n) begin
'b0)
cnt_200us <= 'd0;
'b0)
cnt_200us <= cnt_200us + 'b1;
end
always @(posedge sclk or negedge s_rst_n) begin
'b0)
cnt_cmd <= 'd0;
'b1 && flag_ini_end == 1'b0)
cnt_cmd <= cnt_cmd + 'b1;
end
//cmd_reg
always @(posedge sclk or negedge s_rst_n ) begin
'b0)
cmd_reg <= NOP;
'b1)
case(cnt_cmd)
: cmd_reg <= PRE ;
: cmd_reg <= AREF ;
: cmd_reg <= AREF ;
: cmd_reg <= MSET ;
default : cmd_reg <= NOP ;
endcase
end
'b0;
'b0_0000_0011_0010 : 13'b0_0100_0000_0000;
'b1 : 1'b0;
endmodule
sdram_init
module sdram_top(
//system signals
input sclk ,
input s_rst_n ,
//SDRAM Interfaces
output 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 ,
:] sdram_bank ,
:] sdram_addr ,
:] sdram_dqm ,
:] sdram_dq
);
//==============================================================================\
//*********************Define Parameter and Internal Signal ********************
//==============================================================================/
//init module
wire flag_ini_end ;
:] init_cmd ;
:] init_addr ;
//=============================================================================\
//********************** Main Code ***************************************
//=============================================================================/
'b1;
assign sdram_addr = init_addr;
assign {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = init_cmd ;
'd0;
assign sdram_clk = ~sclk;
sdram_ini sdram_ini_inst(
//systejm signal
.sclk (sclk ),
.s_rst_n (s_rst_n ),
//others
.cmd_reg (init_cmd ),
.sdram_addr (init_addr ),
.flag_ini_end (flag_ini_end )
);
endmodule
sdram_top
这用了一个sdram仿真模型,堪文老师是128的,我的256的不能用,但是我改好了
/***************************************************************************************
作者: 李晟
2003-08-27 V0.1 李晟
添加内存模块倒空功能,在外部需要创建事件:sdram_r ,本SDRAM的内容将会按Bank 顺序damp out 至文件
sdram_data.txt 中
×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××*/
//2004-03-04 陈乃奎 修改原程序中将BANK的数据转存入TXT文件的格式
//2004-03-16 陈乃奎 修改SDRAM 的初始化数据
//2004/04/06 陈乃奎 将SDRAM的操作命令以字符形式表示,以便用MODELSIM监视
//2004/04/19 陈乃奎 修改参数 parameter tAC = 8;
//2010/09/17 罗瑶 修改sdram的大小,数据位宽,dqm宽度;
/****************************************************************************************
*
* File Name: sdram_model.V
* Version: 0.0f
* Date: July 8th, 1999
* Model: BUS Functional
* Simulator: Model Technology (PC version 5.2e PE)
*
* Dependencies: None
*
* Author: Son P. Huynh
* Email: sphuynh@micron.com
* Phone: (208) 368-3825
* Company: Micron Technology, Inc.
* Model: sdram_model (1Meg x 16 x 4 Banks)
*
* Description: 64Mb SDRAM Verilog model
*
* Limitation: - Doesn't check for 4096 cycle refresh
*
* Note: - Set simulator resolution to "ps" accuracy
* - Set Debug = 0 to disable $display messages
*
* Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY
* WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
* A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT.
*
* Copyright ?1998 Micron Semiconductor Products, Inc.
* All rights researved
*
* Rev Author Phone Date Changes
* ---- ---------------------------- ---------- ---------------------------------------
* 0.0f Son Huynh 208-368-3825 07/08/1999 - Fix tWR = 1 Clk + 7.5 ns (Auto)
* Micron Technology Inc. - Fix tWR = 15 ns (Manual)
* - Fix tRP (Autoprecharge to AutoRefresh)
*
* 0.0a Son Huynh 208-368-3825 05/13/1998 - First Release (from 64Mb rev 0.0e)
* Micron Technology Inc.
****************************************************************************************/
`timescale 1ns / 100ps
module sdram_model_plus (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm,Debug);
;
;
;
** -;//1 Meg
: ] Dq;
: ] Addr;
: ] Ba;
input Clk;
input Cke;
input Cs_n;
input Ras_n;
input Cas_n;
input We_n;
: ] Dqm; //高低各8bit
//added by xzli
input Debug;
: ] Bank0 [ : mem_sizes];//存储器类型数据
: ] Bank1 [ : mem_sizes];
: ] Bank2 [ : mem_sizes];
: ] Bank3 [ : mem_sizes];
: ] Bank_addr [ : ]; // Bank Address Pipeline
: ] Col_addr [ : ]; // Column Address Pipeline
: ] Command [ : ]; // Command Operation Pipeline
: ] Dqm_reg0, Dqm_reg1; // DQM Operation Pipeline
: ] B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr;
: ] Mode_reg;
: ] Dq_reg, Dq_dqm;
: ] Col_temp, Burst_counter;
reg Act_b0, Act_b1, Act_b2, Act_b3; // Bank Activate
reg Pc_b0, Pc_b1, Pc_b2, Pc_b3; // Bank Precharge
: ] Bank_precharge [ : ]; // Precharge Command
: ]; // Addr[10] = 1 (All banks)
: ]; // RW AutoPrecharge (Bank)
: ]; // R AutoPrecharge
: ]; // W AutoPrecharge
: ]; // RW AutoPrecharge (Counter)
: ]; // RW Interrupt Read with Auto Precharge
: ]; // RW Interrupt Write with Auto Precharge
reg Data_in_enable;
reg Data_out_enable;
: ] Bank, Previous_bank;
: ] Row;
: ] Col, Col_brst;
// Internal system clock
reg CkeZ, Sys_clk;
:] dd;
// Commands Decode
wire Active_enable = ~Cs_n & ~Ras_n & Cas_n & We_n;
wire Aref_enable = ~Cs_n & ~Ras_n & ~Cas_n & We_n;
wire Burst_term = ~Cs_n & Ras_n & Cas_n & ~We_n;
wire Mode_reg_enable = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n;
wire Prech_enable = ~Cs_n & ~Ras_n & Cas_n & ~We_n;
wire Read_enable = ~Cs_n & Ras_n & ~Cas_n & We_n;
wire Write_enable = ~Cs_n & Ras_n & ~Cas_n & ~We_n;
// Burst Length Decode
] & ~Mode_reg[] & ~Mode_reg[];
] & ~Mode_reg[] & Mode_reg[];
] & Mode_reg[] & ~Mode_reg[];
] & Mode_reg[] & Mode_reg[];
// CAS Latency Decode
] & Mode_reg[] & ~Mode_reg[];
] & Mode_reg[] & Mode_reg[];
// Write Burst Mode
];
wire Debug; // Debug messages : 1 = On; 0 = Off
wire Dq_chk = Sys_clk & Data_in_enable; // Check setup/hold time for DQ
:] mem_d;
event sdram_r,sdram_w,compare;
assign Dq = Dq_reg; // DQ buffer
// Commands Operation
`define ACT
`define NOP
`define READ
`define READ_A
`define WRITE
`define WRITE_A
`define PRECH
`define A_REF
`define BST
`define LMR
// // Timing Parameters for -75 (PC133) and CAS Latency = 2
// parameter tAC = 8; //test 6.5
// parameter tHZ = 7.0;
// parameter tOH = 2.7;
// parameter tMRD = 2.0; // 2 Clk Cycles
// parameter tRAS = 44.0;
// parameter tRC = 66.0;
// parameter tRCD = 20.0;
// parameter tRP = 20.0;
// parameter tRRD = 15.0;
// parameter tWRa = 7.5; // A2 Version - Auto precharge mode only (1 Clk + 7.5 ns)
// parameter tWRp = 0.0; // A2 Version - Precharge mode only (15 ns)
// Timing Parameters for -7 (PC143) and CAS Latency = 3
parameter tAC = 6.5; //test 6.5
parameter tHZ = 5.5;
;
parameter tMRD = 2.0; // 2 Clk Cycles
parameter tRAS = 48.0;
parameter tRC = 70.0;
parameter tRCD = 20.0;
parameter tRP = 20.0;
parameter tRRD = 14.0;
parameter tWRa = 7.5; // A2 Version - Auto precharge mode only (1 Clk + 7.5 ns)
parameter tWRp = 0.0; // A2 Version - Precharge mode only (15 ns)
// Timing Check variable
integer MRD_chk;
: ];
: ];
time RC_chk, RRD_chk;
time RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3;
time RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3;
time RP_chk0, RP_chk1, RP_chk2, RP_chk3;
integer test_file;
//*****display the command of the sdram**************************************
'b0000;
'b0001;
'b0011;
'b0010;
'b0010;
'b0100;
'b0100;
'b0101;
'b0101;
'b0110;
'b0111;
'b1111;
:] sdram_control;
reg cke_temp;
*:] sdram_command;
always@(posedge Clk)
cke_temp<=Cke;
assign sdram_control={Cs_n,Ras_n,Cas_n,We_n};
always@(sdram_control or cke_temp)
begin
case(sdram_control)
Mode_Reg_Set: sdram_command<="Mode_Reg_Set";
Auto_Refresh: sdram_command<="Auto_Refresh";
Row_Active: sdram_command<="Row_Active";
Pre_Charge: sdram_command<="Pre_Charge";
Burst_Stop: sdram_command<="Burst_Stop";
Dsel: sdram_command<="Dsel";
Write: )
sdram_command<="Write";
else
sdram_command<="Write_suspend";
Read: )
sdram_command<="Read";
else
sdram_command<="Read_suspend";
Nop: )
sdram_command<="Nop";
else
sdram_command<="Self_refresh";
default: sdram_command<="Power_down";
endcase
end
//*****************************************************
initial
begin
//test_file=$fopen("test_file.txt");
end
initial
begin
Dq_reg = {data_bits{'bz}};
{Data_in_enable, Data_out_enable} = ;
{Act_b0, Act_b1, Act_b2, Act_b3} = 'b0000;
{Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 'b0000;
{WR_chk[], WR_chk[], WR_chk[], WR_chk[]} = ;
{WR_counter[], WR_counter[], WR_counter[], WR_counter[]} = ;
{RW_interrupt_read[], RW_interrupt_read[], RW_interrupt_read[], RW_interrupt_read[]} = ;
{RW_interrupt_write[], RW_interrupt_write[], RW_interrupt_write[], RW_interrupt_write[]} = ;
{MRD_chk, RC_chk, RRD_chk} = ;
{RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3} = ;
{RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3} = ;
{RP_chk0, RP_chk1, RP_chk2, RP_chk3} = ;
$timeformat (-, , );
//$readmemh("bank0.txt", Bank0);
//$readmemh("bank1.txt", Bank1);
//$readmemh("bank2.txt", Bank2);
//$readmemh("bank3.txt", Bank3);
/*
for(dd=0;dd<=mem_sizes;dd=dd+1)
begin
Bank0[dd]=dd[data_bits - 1 : 0];
Bank1[dd]=dd[data_bits - 1 : 0]+1;
Bank2[dd]=dd[data_bits - 1 : 0]+2;
Bank3[dd]=dd[data_bits - 1 : 0]+3;
end
*/
initial_sdram();
end
task initial_sdram;
input data_sign;
:] data_sign;
;dd<=mem_sizes;dd=dd+)
begin
mem_d = {data_sign,data_sign,data_sign,data_sign,data_sign,data_sign,data_sign,data_sign};
)
begin
Bank0[dd]=mem_d[:];
Bank1[dd]=mem_d[:];
Bank2[dd]=mem_d[:];
Bank3[dd]=mem_d[:];
end
)
begin
Bank0[dd]=mem_d[:];
Bank1[dd]=mem_d[:];
Bank2[dd]=mem_d[:];
Bank3[dd]=mem_d[:];
end
end
endtask
// System clock generator
always
begin
@(posedge Clk)
begin
Sys_clk = CkeZ;
CkeZ = Cke;
end
@(negedge Clk)
begin
Sys_clk = 'b0;
end
end
always @ (posedge Sys_clk) begin
// Internal Commamd Pipelined
Command[] = Command[];
Command[] = Command[];
Command[] = Command[];
Command[] = `NOP;
Col_addr[] = Col_addr[];
Col_addr[] = Col_addr[];
Col_addr[] = Col_addr[];
Col_addr[] = {col_bits{'b0}};
Bank_addr[] = Bank_addr[];
Bank_addr[] = Bank_addr[];
Bank_addr[] = Bank_addr[];
Bank_addr[] = 'b0;
Bank_precharge[] = Bank_precharge[];
Bank_precharge[] = Bank_precharge[];
Bank_precharge[] = Bank_precharge[];
Bank_precharge[] = 'b0;
A10_precharge[] = A10_precharge[];
A10_precharge[] = A10_precharge[];
A10_precharge[] = A10_precharge[];
A10_precharge[] = 'b0;
// Dqm pipeline for Read
Dqm_reg0 = Dqm_reg1;
Dqm_reg1 = Dqm;
// Read or Write with Auto Precharge Counter
] == 'b1) begin
Count_precharge[] = Count_precharge[] + ;
end
] == 'b1) begin
Count_precharge[] = Count_precharge[] + ;
end
] == 'b1) begin
Count_precharge[] = Count_precharge[] + ;
end
] == 'b1) begin
Count_precharge[] = Count_precharge[] + ;
end
// tMRD Counter
MRD_chk = MRD_chk + ;
// tWR Counter for Write
WR_counter[] = WR_counter[] + ;
WR_counter[] = WR_counter[] + ;
WR_counter[] = WR_counter[] + ;
WR_counter[] = WR_counter[] + ;
// Auto Refresh
'b1) begin
if (Debug) $display ("at time %t AREF : Auto Refresh", $time);
// Auto Refresh to Auto Refresh
if (($time - RC_chk < tRC)&&Debug) begin
$display ("at time %t ERROR: tRC violation during Auto Refresh", $time);
end
// Precharge to Auto Refresh
if (($time - RP_chk0 < tRP || $time - RP_chk1 < tRP || $time - RP_chk2 < tRP || $time - RP_chk3 < tRP)&&Debug) begin
$display ("at time %t ERROR: tRP violation during Auto Refresh", $time);
end
// Precharge to Refresh
'b0 || Pc_b3 == 1'b0) begin
$display ("at time %t ERROR: All banks must be Precharge before Auto Refresh", $time);
end
// Record Current tRC time
RC_chk = $time;
end
// Load Mode Register
'b1) begin
// Decode CAS Latency, Burst Length, Burst Type, and Write Burst Mode
'b1 && Pc_b3 == 1'b1) begin
Mode_reg = Addr;
if (Debug) begin
$display ("at time %t LMR : Load Mode Register", $time);
// CAS Latency
: ] == 'b010)
$display (" CAS Latency = 2");
: ] == 'b011)
$display (" CAS Latency = 3");
else
$display (" CAS Latency = Reserved");
// Burst Length
: ] == 'b000)
$display (" Burst Length = 1");
: ] == 'b001)
$display (" Burst Length = 2");
: ] == 'b010)
$display (" Burst Length = 4");
: ] == 'b011)
$display (" Burst Length = 8");
: ] == 'b0111)
$display (" Burst Length = Full");
else
$display (" Burst Length = Reserved");
// Burst Type
] == 'b0)
$display (" Burst Type = Sequential");
] == 'b1)
$display (" Burst Type = Interleaved");
else
$display (" Burst Type = Reserved");
// Write Burst Mode
] == 'b0)
$display (" Write Burst Mode = Programmed Burst Length");
] == 'b1)
$display (" Write Burst Mode = Single Location Access");
else
$display (" Write Burst Mode = Reserved");
end
end else begin
$display ("at time %t ERROR: all banks must be Precharge before Load Mode Register", $time);
end
// REF to LMR
if ($time - RC_chk < tRC) begin
$display ("at time %t ERROR: tRC violation during Load Mode Register", $time);
end
// LMR to LMR
if (MRD_chk < tMRD) begin
$display ("at time %t ERROR: tMRD violation during Load Mode Register", $time);
end
MRD_chk = ;
end
// Active Block (Latch Bank Address and Row Address)
'b1) begin
'b00 && Pc_b0 == 1'b1) begin
{Act_b0, Pc_b0} = 'b10;
B0_row_addr = Addr [addr_bits - : ];
RCD_chk0 = $time;
RAS_chk0 = $time;
if (Debug) $display ("at time %t ACT : Bank = 0 Row = %d", $time, Addr);
// Precharge to Activate Bank 0
if ($time - RP_chk0 < tRP) begin
$display ("at time %t ERROR: tRP violation during Activate bank 0", $time);
end
'b01 && Pc_b1 == 1'b1) begin
{Act_b1, Pc_b1} = 'b10;
B1_row_addr = Addr [addr_bits - : ];
RCD_chk1 = $time;
RAS_chk1 = $time;
if (Debug) $display ("at time %t ACT : Bank = 1 Row = %d", $time, Addr);
// Precharge to Activate Bank 1
if ($time - RP_chk1 < tRP) begin
$display ("at time %t ERROR: tRP violation during Activate bank 1", $time);
end
'b10 && Pc_b2 == 1'b1) begin
{Act_b2, Pc_b2} = 'b10;
B2_row_addr = Addr [addr_bits - : ];
RCD_chk2 = $time;
RAS_chk2 = $time;
if (Debug) $display ("at time %t ACT : Bank = 2 Row = %d", $time, Addr);
// Precharge to Activate Bank 2
if ($time - RP_chk2 < tRP) begin
$display ("at time %t ERROR: tRP violation during Activate bank 2", $time);
end
'b11 && Pc_b3 == 1'b1) begin
{Act_b3, Pc_b3} = 'b10;
B3_row_addr = Addr [addr_bits - : ];
RCD_chk3 = $time;
RAS_chk3 = $time;
if (Debug) $display ("at time %t ACT : Bank = 3 Row = %d", $time, Addr);
// Precharge to Activate Bank 3
if ($time - RP_chk3 < tRP) begin
$display ("at time %t ERROR: tRP violation during Activate bank 3", $time);
end
'b00 && Pc_b0 == 1'b0) begin
$display ("at time %t ERROR: Bank 0 is not Precharged.", $time);
'b01 && Pc_b1 == 1'b0) begin
$display ("at time %t ERROR: Bank 1 is not Precharged.", $time);
'b10 && Pc_b2 == 1'b0) begin
$display ("at time %t ERROR: Bank 2 is not Precharged.", $time);
'b11 && Pc_b3 == 1'b0) begin
$display ("at time %t ERROR: Bank 3 is not Precharged.", $time);
end
// Active Bank A to Active Bank B
if ((Previous_bank != Ba) && ($time - RRD_chk < tRRD)) begin
$display ("at time %t ERROR: tRRD violation during Activate bank = %d", $time, Ba);
end
// Load Mode Register to Active
if (MRD_chk < tMRD ) begin
$display ("at time %t ERROR: tMRD violation during Activate bank = %d", $time, Ba);
end
// Auto Refresh to Activate
if (($time - RC_chk < tRC)&&Debug) begin
$display ("at time %t ERROR: tRC violation during Activate bank = %d", $time, Ba);
end
// Record variables for checking violation
RRD_chk = $time;
Previous_bank = Ba;
end
// Precharge Block
'b1) begin
] == 'b1) begin
{Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 'b1111;
{Act_b0, Act_b1, Act_b2, Act_b3} = 'b0000;
RP_chk0 = $time;
RP_chk1 = $time;
RP_chk2 = $time;
RP_chk3 = $time;
if (Debug) $display ("at time %t PRE : Bank = ALL",$time);
// Activate to Precharge all banks
if (($time - RAS_chk0 < tRAS) || ($time - RAS_chk1 < tRAS) ||
($time - RAS_chk2 < tRAS) || ($time - RAS_chk3 < tRAS)) begin
$display ("at time %t ERROR: tRAS violation during Precharge all bank", $time);
end
// tWR violation check for write
] < tWRp) || ($] < tWRp) ||
($] < tWRp) || ($] < tWRp)) begin
$display ("at time %t ERROR: tWR violation during Precharge all bank", $time);
end
] == 'b0) begin
'b00) begin
{Pc_b0, Act_b0} = 'b10;
RP_chk0 = $time;
if (Debug) $display ("at time %t PRE : Bank = 0",$time);
// Activate to Precharge Bank 0
if ($time - RAS_chk0 < tRAS) begin
$display ("at time %t ERROR: tRAS violation during Precharge bank 0", $time);
end
'b01) begin
{Pc_b1, Act_b1} = 'b10;
RP_chk1 = $time;
if (Debug) $display ("at time %t PRE : Bank = 1",$time);
// Activate to Precharge Bank 1
if ($time - RAS_chk1 < tRAS) begin
$display ("at time %t ERROR: tRAS violation during Precharge bank 1", $time);
end
'b10) begin
{Pc_b2, Act_b2} = 'b10;
RP_chk2 = $time;
if (Debug) $display ("at time %t PRE : Bank = 2",$time);
// Activate to Precharge Bank 2
if ($time - RAS_chk2 < tRAS) begin
$display ("at time %t ERROR: tRAS violation during Precharge bank 2", $time);
end
'b11) begin
{Pc_b3, Act_b3} = 'b10;
RP_chk3 = $time;
if (Debug) $display ("at time %t PRE : Bank = 3",$time);
// Activate to Precharge Bank 3
if ($time - RAS_chk3 < tRAS) begin
$display ("at time %t ERROR: tRAS violation during Precharge bank 3", $time);
end
end
// tWR violation check for write
if ($time - WR_chk[Ba] < tWRp) begin
$display ("at time %t ERROR: tWR violation during Precharge bank %d", $time, Ba);
end
end
// Terminate a Write Immediately (if same bank or all banks)
'b1 && (Bank == Ba || Addr[10] == 1'b1)) begin
Data_in_enable = 'b0;
end
// Precharge Command Pipeline for Read
'b1) begin
Command[] = `PRECH;
Bank_precharge[] = Ba;
A10_precharge[] = Addr[];
'b1) begin
Command[] = `PRECH;
Bank_precharge[] = Ba;
A10_precharge[] = Addr[];
end
end
// Burst terminate
'b1) begin
// Terminate a Write Immediately
'b1) begin
Data_in_enable = 'b0;
end
// Terminate a Read Depend on CAS Latency
'b1) begin
Command[] = `BST;
'b1) begin
Command[] = `BST;
end
if (Debug) $display ("at time %t BST : Burst Terminate",$time);
end
// Read, Write, Column Latch
'b1 || Write_enable == 1'b1) begin
// Check to see if bank is open (ACT)
'b01 && Pc_b1 == 1'b1) ||
(Ba == 'b11 && Pc_b3 == 1'b1)) begin
$display("at time %t ERROR: Cannot Read or Write - Bank %d is not Activated", $time, Ba);
end
// Activate to Read or Write
'b00) && ($time - RCD_chk0 < tRCD))
$display("at time %t ERROR: tRCD violation during Read or Write to Bank 0", $time);
'b01) && ($time - RCD_chk1 < tRCD))
$display("at time %t ERROR: tRCD violation during Read or Write to Bank 1", $time);
'b10) && ($time - RCD_chk2 < tRCD))
$display("at time %t ERROR: tRCD violation during Read or Write to Bank 2", $time);
'b11) && ($time - RCD_chk3 < tRCD))
$display("at time %t ERROR: tRCD violation during Read or Write to Bank 3", $time);
// Read Command
'b1) begin
// CAS Latency pipeline
'b1) begin
] == 'b1) begin
Command[] = `READ_A;
end else begin
Command[] = `READ;
end
Col_addr[] = Addr;
Bank_addr[] = Ba;
'b1) begin
] == 'b1) begin
Command[] = `READ_A;
end else begin
Command[] = `READ;
end
Col_addr[] = Addr;
Bank_addr[] = Ba;
end
// Read interrupt Write (terminate Write immediately)
'b1) begin
Data_in_enable = 'b0;
end
// Write Command
'b1) begin
] == 'b1) begin
Command[] = `WRITE_A;
end else begin
Command[] = `WRITE;
end
Col_addr[] = Addr;
Bank_addr[] = Ba;
// Write interrupt Write (terminate Write immediately)
'b1) begin
Data_in_enable = 'b0;
end
// Write interrupt Read (terminate Read immediately)
'b1) begin
Data_out_enable = 'b0;
end
end
// Interrupting a Write with Autoprecharge
'b1 && Write_precharge[Bank] == 1'b1) begin
RW_interrupt_write[Bank] = 'b1;
if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Write Bank %d with Autoprecharge", $time, Ba, Bank);
end
// Interrupting a Read with Autoprecharge
'b1 && Read_precharge[Bank] == 1'b1) begin
RW_interrupt_read[Bank] = 'b1;
if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Read Bank %d with Autoprecharge", $time, Ba, Bank);
end
// Read or Write with Auto Precharge
] == 'b1) begin
Auto_precharge[Ba] = 'b1;
Count_precharge[Ba] = ;
'b1) begin
Read_precharge[Ba] = 'b1;
'b1) begin
Write_precharge[Ba] = 'b1;
end
end
end
// Read with Auto Precharge Calculation
// The device start internal precharge:
// 1. CAS Latency - 1 cycles before last burst
// and 2. Meet minimum tRAS requirement
// or 3. Interrupt by a Read or Write (with or without AutoPrecharge)
] == 'b1) && (Read_precharge[0] == 1'b1)) begin
if ((($time - RAS_chk0 >= tRAS) && // Case 2
((Burst_length_1 == 'b1 && Count_precharge[0] >= 1) || // Case 1
(Burst_length_2 == 'b1 && Count_precharge[0] >= 2) ||
(Burst_length_4 == 'b1 && Count_precharge[0] >= 4) ||
(Burst_length_8 == 'b1 && Count_precharge[0] >= 8))) ||
(RW_interrupt_read[] == 'b1)) begin // Case 3
Pc_b0 = 'b1;
Act_b0 = 'b0;
RP_chk0 = $time;
Auto_precharge[] = 'b0;
Read_precharge[] = 'b0;
RW_interrupt_read[] = 'b0;
if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time);
end
end
] == 'b1) && (Read_precharge[1] == 1'b1)) begin
if ((($time - RAS_chk1 >= tRAS) &&
((Burst_length_1 == 'b1 && Count_precharge[1] >= 1) ||
(Burst_length_2 == 'b1 && Count_precharge[1] >= 2) ||
(Burst_length_4 == 'b1 && Count_precharge[1] >= 4) ||
(Burst_length_8 == 'b1 && Count_precharge[1] >= 8))) ||
(RW_interrupt_read[] == 'b1)) begin
Pc_b1 = 'b1;
Act_b1 = 'b0;
RP_chk1 = $time;
Auto_precharge[] = 'b0;
Read_precharge[] = 'b0;
RW_interrupt_read[] = 'b0;
if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time);
end
end
] == 'b1) && (Read_precharge[2] == 1'b1)) begin
if ((($time - RAS_chk2 >= tRAS) &&
((Burst_length_1 == 'b1 && Count_precharge[2] >= 1) ||
(Burst_length_2 == 'b1 && Count_precharge[2] >= 2) ||
(Burst_length_4 == 'b1 && Count_precharge[2] >= 4) ||
(Burst_length_8 == 'b1 && Count_precharge[2] >= 8))) ||
(RW_interrupt_read[] == 'b1)) begin
Pc_b2 = 'b1;
Act_b2 = 'b0;
RP_chk2 = $time;
Auto_precharge[] = 'b0;
Read_precharge[] = 'b0;
RW_interrupt_read[] = 'b0;
if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time);
end
end
] == 'b1) && (Read_precharge[3] == 1'b1)) begin
if ((($time - RAS_chk3 >= tRAS) &&
((Burst_length_1 == 'b1 && Count_precharge[3] >= 1) ||
(Burst_length_2 == 'b1 && Count_precharge[3] >= 2) ||
(Burst_length_4 == 'b1 && Count_precharge[3] >= 4) ||
(Burst_length_8 == 'b1 && Count_precharge[3] >= 8))) ||
(RW_interrupt_read[] == 'b1)) begin
Pc_b3 = 'b1;
Act_b3 = 'b0;
RP_chk3 = $time;
Auto_precharge[] = 'b0;
Read_precharge[] = 'b0;
RW_interrupt_read[] = 'b0;
if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time);
end
end
// Internal Precharge or Bst
] == `PRECH) begin // Precharge terminate a read with same bank or all banks
] == Bank || A10_precharge[] == 'b1) begin
'b1) begin
Data_out_enable = 'b0;
end
end
] == `BST) begin // BST terminate a read to current bank
'b1) begin
Data_out_enable = 'b0;
end
end
'b0) begin
Dq_reg <= #tOH {data_bits{'bz}};
end
// Detect Read or Write command
] == `READ || Command[] == `READ_A) begin
Bank = Bank_addr[];
Col = Col_addr[];
Col_brst = Col_addr[];
] == 'b00) begin
Row = B0_row_addr;
] == 'b01) begin
Row = B1_row_addr;
] == 'b10) begin
Row = B2_row_addr;
] == 'b11) begin
Row = B3_row_addr;
end
Burst_counter = ;
Data_in_enable = 'b0;
Data_out_enable = 'b1;
] == `WRITE || Command[] == `WRITE_A) begin
Bank = Bank_addr[];
Col = Col_addr[];
Col_brst = Col_addr[];
] == 'b00) begin
Row = B0_row_addr;
] == 'b01) begin
Row = B1_row_addr;
] == 'b10) begin
Row = B2_row_addr;
] == 'b11) begin
Row = B3_row_addr;
end
Burst_counter = ;
Data_in_enable = 'b1;
Data_out_enable = 'b0;
end
// DQ buffer (Driver/Receiver)
'b1) begin // Writing Data to Memory
// Array buffer
'b00) Dq_dqm [data_bits - 1 : 0] = Bank0 [{Row, Col}];
'b01) Dq_dqm [data_bits - 1 : 0] = Bank1 [{Row, Col}];
'b10) Dq_dqm [data_bits - 1 : 0] = Bank2 [{Row, Col}];
'b11) Dq_dqm [data_bits - 1 : 0] = Bank3 [{Row, Col}];
// Dqm operation
] == 'b0) Dq_dqm [ 7 : 0] = Dq [ 7 : 0];
] == 'b0) Dq_dqm [15 : 8] = Dq [15 : 8];
//if (Dqm[2] == 1'b0) Dq_dqm [23 : 16] = Dq [23 : 16];
// if (Dqm[3] == 1'b0) Dq_dqm [31 : 24] = Dq [31 : 24];
// Write to memory
'b00) Bank0 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0];
'b01) Bank1 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0];
'b10) Bank2 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0];
'b11) Bank3 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0];
:]=='h4)
$display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
//$fdisplay(test_file,"bank:%h row:%h col:%h write:%h",Bank,Row,Col,Dq_dqm);
// Output result
'b1111) begin
if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
end else begin
if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = %d, Dqm = %b", $time, Bank, Row, Col, Dq_dqm, Dqm);
// Record tWR time and reset counter
WR_chk [Bank] = $time;
WR_counter [Bank] = ;
end
// Advance burst counter subroutine
#tHZ Burst;
'b1) begin // Reading Data from Memory
//$display("%h , %h, %h",Bank0,Row,Col);
// Array buffer
'b00) Dq_dqm [data_bits - 1 : 0] = Bank0 [{Row, Col}];
'b01) Dq_dqm [data_bits - 1 : 0] = Bank1 [{Row, Col}];
'b10) Dq_dqm [data_bits - 1 : 0] = Bank2 [{Row, Col}];
'b11) Dq_dqm [data_bits - 1 : 0] = Bank3 [{Row, Col}];
// Dqm operation
] == 'b1) Dq_dqm [ 7 : 0] = 8'bz;
] == 'b1) Dq_dqm [15 : 8] = 8'bz;
] == 'b1) Dq_dqm [23 : 16] = 8'bz;
] == 'b1) Dq_dqm [31 : 24] = 8'bz;
// Display result
Dq_reg [data_bits - : ] = #tAC Dq_dqm [data_bits - : ];
'b1111) begin
if (Debug) $display("at time %t READ : Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
end else begin
if (Debug) $display("at time %t READ : Bank = %d Row = %d, Col = %d, Data = %d, Dqm = %b", $time, Bank, Row, Col, Dq_reg, Dqm_reg0);
end
// Advance burst counter subroutine
Burst;
end
end
// Write with Auto Precharge Calculation
// The device start internal precharge:
// 1. tWR Clock after last burst
// and 2. Meet minimum tRAS requirement
// or 3. Interrupt by a Read or Write (with or without AutoPrecharge)
]) begin
] == 'b1) && (Write_precharge[0] == 1'b1)) begin
if ((($time - RAS_chk0 >= tRAS) && // Case 2
(((Burst_length_1 == ] >= ) || // Case 1
(Burst_length_2 == 'b1 && Count_precharge [0] >= 2) ||
(Burst_length_4 == 'b1 && Count_precharge [0] >= 4) ||
(Burst_length_8 == 'b1 && Count_precharge [0] >= 8))) ||
(RW_interrupt_write[] == 'b1 && WR_counter[0] >= 2)) begin // Case 3 (stop count when interrupt)
Auto_precharge[] = 'b0;
Write_precharge[] = 'b0;
RW_interrupt_write[] = 'b0;
#tWRa; // Wait for tWR
Pc_b0 = 'b1;
Act_b0 = 'b0;
RP_chk0 = $time;
if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time);
end
end
end
]) begin
] == 'b1) && (Write_precharge[1] == 1'b1)) begin
if ((($time - RAS_chk1 >= tRAS) &&
(((Burst_length_1 == ] >= ) ||
(Burst_length_2 == 'b1 && Count_precharge [1] >= 2) ||
(Burst_length_4 == 'b1 && Count_precharge [1] >= 4) ||
(Burst_length_8 == 'b1 && Count_precharge [1] >= 8))) ||
(RW_interrupt_write[] == 'b1 && WR_counter[1] >= 2)) begin
Auto_precharge[] = 'b0;
Write_precharge[] = 'b0;
RW_interrupt_write[] = 'b0;
#tWRa; // Wait for tWR
Pc_b1 = 'b1;
Act_b1 = 'b0;
RP_chk1 = $time;
if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time);
end
end
end
]) begin
] == 'b1) && (Write_precharge[2] == 1'b1)) begin
if ((($time - RAS_chk2 >= tRAS) &&
(((Burst_length_1 == ] >= ) ||
(Burst_length_2 == 'b1 && Count_precharge [2] >= 2) ||
(Burst_length_4 == 'b1 && Count_precharge [2] >= 4) ||
(Burst_length_8 == 'b1 && Count_precharge [2] >= 8))) ||
(RW_interrupt_write[] == 'b1 && WR_counter[2] >= 2)) begin
Auto_precharge[] = 'b0;
Write_precharge[] = 'b0;
RW_interrupt_write[] = 'b0;
#tWRa; // Wait for tWR
Pc_b2 = 'b1;
Act_b2 = 'b0;
RP_chk2 = $time;
if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time);
end
end
end
]) begin
] == 'b1) && (Write_precharge[3] == 1'b1)) begin
if ((($time - RAS_chk3 >= tRAS) &&
(((Burst_length_1 == ] >= ) ||
(Burst_length_2 == 'b1 && Count_precharge [3] >= 2) ||
(Burst_length_4 == 'b1 && Count_precharge [3] >= 4) ||
(Burst_length_8 == 'b1 && Count_precharge [3] >= 8))) ||
(RW_interrupt_write[] == 'b1 && WR_counter[3] >= 2)) begin
Auto_precharge[] = 'b0;
Write_precharge[] = 'b0;
RW_interrupt_write[] = 'b0;
#tWRa; // Wait for tWR
Pc_b3 = 'b1;
Act_b3 = 'b0;
RP_chk3 = $time;
if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time);
end
end
end
task Burst;
begin
// Advance Burst Counter
Burst_counter = Burst_counter + ;
// Burst Type
] == 'b0) begin // Sequential Burst
Col_temp = Col + ;
] == 'b1) begin // Interleaved Burst
Col_temp[] = Burst_counter[] ^ Col_brst[];
Col_temp[] = Burst_counter[] ^ Col_brst[];
Col_temp[] = Burst_counter[] ^ Col_brst[];
end
// Burst Length
if (Burst_length_2) begin // Burst Length = 2
Col [] = Col_temp [];
end else if (Burst_length_4) begin // Burst Length = 4
Col [ : ] = Col_temp [ : ];
end else if (Burst_length_8) begin // Burst Length = 8
Col [ : ] = Col_temp [ : ];
end else begin // Burst Length = FULL
Col = Col_temp;
end
// Burst Read Single Write
'b1) begin
Data_in_enable = 'b0;
end
// Data Counter
'b1) begin
) begin
Data_in_enable = 'b0;
Data_out_enable = 'b0;
end
'b1) begin
) begin
Data_in_enable = 'b0;
Data_out_enable = 'b0;
end
'b1) begin
) begin
Data_in_enable = 'b0;
Data_out_enable = 'b0;
end
'b1) begin
) begin
Data_in_enable = 'b0;
Data_out_enable = 'b0;
end
end
end
endtask
//**********************将SDRAM内的数据直接输出到外部文件*******************************//
/*
integer sdram_data,ind;
always@(sdram_r)
begin
sdram_data=$fopen("sdram_data.txt");
$display("Sdram dampout begin ",sdram_data);
// $fdisplay(sdram_data,"Bank0:");
for(ind=0;ind<=mem_sizes;ind=ind+1)
$fdisplay(sdram_data,"%h %b",ind,Bank0[ind]);
// $fdisplay(sdram_data,"Bank1:");
for(ind=0;ind<=mem_sizes;ind=ind+1)
$fdisplay(sdram_data,"%h %b",ind,Bank1[ind]);
// $fdisplay(sdram_data,"Bank2:");
for(ind=0;ind<=mem_sizes;ind=ind+1)
$fdisplay(sdram_data,"%h %b",ind,Bank2[ind]);
// $fdisplay(sdram_data,"Bank3:");
for(ind=0;ind<=mem_sizes;ind=ind+1)
$fdisplay(sdram_data,"%h %b",ind,Bank3[ind]);
$fclose("sdram_data.txt");
//->compare;
end
*/
integer sdram_data,sdram_mem;
:] aa,cc;
:] bb,ee;
always@(sdram_r)
begin
$display("Sdram dampout begin ",$realtime);
sdram_data=$fopen("sdram_data.txt");
;aa<*(mem_sizes+);aa=aa+)
begin
bb=aa[:];
if(aa<=mem_sizes)
$fdisplay(sdram_data,"%0d %0h",aa,Bank0[bb]);
*mem_sizes+)
$fdisplay(sdram_data,"%0d %0h",aa,Bank1[bb]);
*mem_sizes+)
$fdisplay(sdram_data,"%0d %0h",aa,Bank2[bb]);
else
$fdisplay(sdram_data,"%0d %0h",aa,Bank3[bb]);
end
$fclose("sdram_data.txt");
sdram_mem=$fopen("sdram_mem.txt");
;cc<*(mem_sizes+);cc=cc+)
begin
ee=cc[:];
if(cc<=mem_sizes)
$fdisplay(sdram_mem,"%0h",Bank0[ee]);
*mem_sizes+)
$fdisplay(sdram_mem,"%0h",Bank1[ee]);
*mem_sizes+)
$fdisplay(sdram_mem,"%0h",Bank2[ee]);
else
$fdisplay(sdram_mem,"%0h",Bank3[ee]);
end
$fclose("sdram_mem.txt");
end
// // Timing Parameters for -75 (PC133) and CAS Latency = 2
// specify
// specparam
//// tAH = 0.8, // Addr, Ba Hold Time
//// tAS = 1.5, // Addr, Ba Setup Time
//// tCH = 2.5, // Clock High-Level Width
//// tCL = 2.5, // Clock Low-Level Width
////// tCK = 10.0, // Clock Cycle Time 100mhz
////// tCK = 7.5, // Clock Cycle Time 133mhz
//// tCK = 7, // Clock Cycle Time 143mhz
//// tDH = 0.8, // Data-in Hold Time
//// tDS = 1.5, // Data-in Setup Time
//// tCKH = 0.8, // CKE Hold Time
//// tCKS = 1.5, // CKE Setup Time
//// tCMH = 0.8, // CS#, RAS#, CAS#, WE#, DQM# Hold Time
//// tCMS = 1.5; // CS#, RAS#, CAS#, WE#, DQM# Setup Time
// tAH = 1, // Addr, Ba Hold Time
// tAS = 1.5, // Addr, Ba Setup Time
// tCH = 1, // Clock High-Level Width
// tCL = 3, // Clock Low-Level Width
//// tCK = 10.0, // Clock Cycle Time 100mhz
//// tCK = 7.5, // Clock Cycle Time 133mhz
// tCK = 7, // Clock Cycle Time 143mhz
// tDH = 1, // Data-in Hold Time
// tDS = 2, // Data-in Setup Time
// tCKH = 1, // CKE Hold Time
// tCKS = 2, // CKE Setup Time
// tCMH = 0.8, // CS#, RAS#, CAS#, WE#, DQM# Hold Time
// tCMS = 1.5; // CS#, RAS#, CAS#, WE#, DQM# Setup Time
// $width (posedge Clk, tCH);
// $width (negedge Clk, tCL);
// $period (negedge Clk, tCK);
// $period (posedge Clk, tCK);
// $setuphold(posedge Clk, Cke, tCKS, tCKH);
// $setuphold(posedge Clk, Cs_n, tCMS, tCMH);
// $setuphold(posedge Clk, Cas_n, tCMS, tCMH);
// $setuphold(posedge Clk, Ras_n, tCMS, tCMH);
// $setuphold(posedge Clk, We_n, tCMS, tCMH);
// $setuphold(posedge Clk, Addr, tAS, tAH);
// $setuphold(posedge Clk, Ba, tAS, tAH);
// $setuphold(posedge Clk, Dqm, tCMS, tCMH);
// $setuphold(posedge Dq_chk, Dq, tDS, tDH);
// endspecify
endmodule
sdram_model_plus
7.最后附上仿真结果
打印信息,简单明了,这是我喜欢的风格

再来看看波形吧

完美,忙活了一天有些坑真的自己填,因为每填完一个坑,起身更强大,明天继续
2018/730
今天继续更新,有很多事耽搁了两天
二.仲裁机制和刷新操作
1.刷新操作是sdram必须的操作,使用不当数据指定丢失,具体为什么自己去查一下,我省的废话了。
既然是刷新,那么就应该有刷新的周期,这个怎么计算呢,打开datasheet,看图。红框意思是64ms内要进行8192次刷新,那么刷新周期大约7.8us

2.该刷新时序以及命令了
看下面的时序图等初始化完成后,刷新操作的第一步就是预充电(precharge),然后等tRP时间进行auto refresh(自刷新),后面再一次刷新和active都不用进行。前面哪个时间自己对应手册查一下,一般不会有错
这儿提一下,在预充电的时候,地址引脚要同时进行操作,A0~A9、A11、A12不用管,只对A10进行操作,如果A10位1,就是对所有bank进行充电,为0时选择bank进行充电,我们是为1。

3.刷新就说完了,该附上源代码了
module sdram_aref(
//system signals
input sclk ,
input s_rst_n ,
//comunicat with ARBIT
input ref_en ,
output wire ref_req ,
output wire flag_ref_end ,
//others
:] aref_cmd ,
:] sdram_addr ,
input flag_init_end
);
//==============================================================================\
//*********************Define Parameter and Internal Signal ********************
//==============================================================================/
;
'b0001 ;
'b0111 ;
'b0010 ;
:] cmd_cnt ;
:] ref_cnt ;
reg flag_ref ;
//=============================================================================\
//********************** Main Code ***************************************
//=============================================================================/
always @(posedge sclk or negedge s_rst_n) begin
'b0)
ref_cnt <= 'd0;
else if(ref_cnt >= DELAY_78us)
ref_cnt <= 'd0;
'b1)
ref_cnt <= ref_cnt +'b1;
end
always @(posedge sclk or negedge s_rst_n) begin
'b0)
flag_ref <= 'b0;
'b1)
flag_ref <= 'b0;
'b1)
flag_ref <= 'b1;
end
always @(posedge sclk or negedge s_rst_n ) begin
'b0)
cmd_cnt <= 'd0;
'b1)
cmd_cnt <= cmd_cnt + 'b1;
else
cmd_cnt <= 'd0;
end
always @(posedge sclk or negedge s_rst_n) begin
'b0)
aref_cmd <= CMD_NOP;
else case(cmd_cnt)
: aref_cmd <= CMD_PRE;
: aref_cmd <= CMD_AREF;
default:aref_cmd <= CMD_NOP;
endcase
end
'b0;
'd0_0100_0000_0000;
'b1 : 1'b0;
endmodule
sdram_aref
4.仲裁机制
为什么要这个仲裁机制,sdram工作是有刷新、写和读3个操作,我们需要这个仲裁机制来协调这三个操作,引用邓堪文老师一个图,大家一看就应该很明白了

5.具体的操作在sdram_top模块里,附上源码自己研究一下,这只写了三种状态,其他状态后面学习了在更新
module sdram_top(
//system signals
input sclk ,
input s_rst_n ,
//SDRAM Interfaces
output 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 ,
:] sdram_bank ,
:] sdram_addr ,
:] sdram_dqm ,
:] sdram_dq
);
//==============================================================================\
//*********************Define Parameter and Internal Signal ********************
//==============================================================================/
'b0_0001 ;
'b0_0010 ;
'b0_0100 ;
//init module
wire flag_init_end ;
:] init_cmd ;
:] init_addr ;
//
:] state ;
//refresh module
wire ref_req ;
wire flag_ref_end ;
reg ref_en ;
:] ref_cmd ;
:] ref_addr ;
//=============================================================================\
//********************** Main Code ***************************************
//=============================================================================/
always @(posedge sclk or negedge s_rst_n) begin
'b0)
state <= IDLE;
else case(state)
IDLE:
'b1)
state <= ARBIT;
else
state <= IDLE;
ARBIT:
'b1)
state <= AREF;
else
state <= ARBIT;
AREF:
'b1)
state <= ARBIT;
else
state <=AREF;
default:
state <= IDLE;
endcase
end
//ref_en
always @(posedge sclk or negedge s_rst_n) begin
'b0)
ref_en <= 'b0;
'b1)
ref_en <= 'b1;
else
ref_en <= 'b0;
end
'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 : ref_cmd;
'd0;
assign sdram_clk = ~sclk;
sdram_ini sdram_ini_inst(
//systejm sign
.sclk (sclk ),
.s_rst_n (s_rst_n ),
//others
.cmd_reg (init_cmd ),
.sdram_addr (init_addr ),
.flag_init_end (flag_init_end )
);
sdram_aref sdram_aref_inst(
//system signals
.sclk (sclk ),
.s_rst_n (s_rst_n ),
//comunicat with ARBIT
.ref_en (ref_en ),
.ref_req (ref_req ),
.flag_ref_end (flag_ref_end ),
//others
.aref_cmd (ref_cmd ),
.sdram_addr (ref_addr ),
.flag_init_end (flag_init_end )
);
endmodule
sdram_top
6.最后老规矩放上仿真结果以及仿真波形图
初始化没有错,刷星也一直进行,没有错误

在看看波形图,没次看到这些信号就觉得自己就是个大牛,哈哈哈! 自恋了,但是还是个入了门的菜鸡。看图信号和数据都没问题,完美!

2018.9.14
首先骂一下狗逼学校都要写完了停电了。我靠全没了,暑假就停了我那么久的网,还到处开挖,挖金子啊绝地三尺关键是堵道。无语了。。。
消气还是重写吧,一个多月了,打算每做好一个功能就更的,可惜就该这个狗逼学校事多还停水停网,但是我也没停下。现在补上吧,下午都快写完了突然停电主机关机了,呵呵,现在就这样了
首先看一下现在做好的图片显示系统,用串口发送640*480的图片给FPGA,波特率是1562500,最快的了,VGA驱动显示屏。
说实话我不想再从写了,很烦,还有很多事要忙,真心要学的可以私聊我!


基于fpga的256m的SDRAM控制器的更多相关文章
- 学习FPGA有必要写SDRAM控制器吗?
在学习FPGA的过程中,注意是在学习过程中,联系FPGA的使用技巧,强烈建议尝试设计一个SDRAM控制器,不要使用IP核. 学习SDRAM控制器设计,能让你掌握很多知识. 更好的使用状态机去精准控制时 ...
- 基于FPGA的XPT2046触摸控制器设计
基于FPGA的XPT2046触摸控制器设计 小梅哥编写,未经许可,文章内容和所涉及代码不得用于其他商业销售的板卡 本实例所涉及代码均可通过向 xiaomeige_fpga@foxmail.com 发 ...
- 基于FPGA的SPI FLASH控制器设计
1.SPI FLASH的基本特征 本文实现用FPGA来设计SPI FLASH,FLASH型号为W25Q128BV.支持3种通信方式,SPI.Dual SPI和Quad SPI.FLASH的存储单元无法 ...
- 继续死磕SDRAM控制器
SDRAM控制器 博主上一篇介绍了一些SDRAM的基本原理是否有必要学习使用纯Verilog写一个SDRAM控制器,接下来记录SDRAM控制器的工作原理.首先是上电初始化. 上电初始化 时序图中,tR ...
- 基于FPGA的1553B通信模块的设计(转)
reference:http://www.21ic.com/app/eda/201808/798483.htm https://www.milstd1553.com/ [导读] 摘 要: 提出一种将F ...
- 基于FPGA的PCIe接口实现(具体讲解了数据流向)
时间:2014-12-09 来源:西安电子科技大学电子工程学院 作者:姜 宁,陈建春,王 沛,石 婷 摘要 PCI Express是一种高性能互连协议,被广泛应用于网络适配.图形加速器.网络存储.大数 ...
- 基于FPGA的DDR3多端口读写存储管理系统设计
基于FPGA的DDR3多端口读写存储管理系统设计 文章出处:电子技术设计 发布时间: 2015/03/12 | 1747 次阅读 每天新产品 时刻新体验专业薄膜开关打样工厂,12小时加急出货 机载 ...
- 基于MIG IP核的DDR3控制器(一)
最近学习了DDR3控制器的使用,也用着DDR完成了一些简单工作,想着以后一段可能只用封装过后的IP核,可能会忘记DDR3控制器的一些内容,想着把这个DDR控制器的编写过程记录下来,便于我自己以后查看吧 ...
- 基于FPGA的OLED真彩色动态图像显示的实现
源:基于FPGA的OLED真彩色动态图像显示的实现 作为第3代显示器,有机电致发光器件(Organic Light Emitting Diode,OLED)由于其主动发光.响应快.高亮度.全视角.直流 ...
随机推荐
- TransModeler 交通仿真软件
1.系统概述 TransModeler是美国Caliper公司开发的一个功能强大而操作灵活的交通仿真软件包,广泛适用于各类交通规划和交通仿真建模任务.TransModeler独特之处在于它提供了宏观/ ...
- Python科学计算的瑞士军刀——Anaconda 安装与配置
Introduce Python是一种强大的编程语言.其提供了非常多用于科学计算的模块,常见的包含numpy.scipy和matplotlib.要利用Python进行科学计算.就须要一一安装所需的模块 ...
- iOS 中删除cookie的正确做法
需求:删除 qq 登录的 cookie,保证下次打开 qq 登录页面不会默认登录 实现: NSString *url =@"https://w.mail.qq.com/cgi-bi ...
- hdu 5325 Crazy Bobo dfs
// hdu 5325 Crazy Bobo // // 题目大意: // // 给你一棵树,树上每一个节点都有一个权值w,选择尽可能多的节点, // 这些节点相互联通,而且依照权值升序排序之后得到节 ...
- ios4--UIView的常见属性(尺寸和位置)
// // ViewController.m // 08-UIView的常见属性(尺寸和位置) // // frame:相对于父控件左上角定位 // bounds:改变长宽,左上角是相对于自己 // ...
- YTU 2782: 用数字造数字
2782: 用数字造数字 时间限制: 1 Sec 内存限制: 128 MB 提交: 191 解决: 160 题目描述 输入一个3位以上的整数,求其中最大的数字最小的数字之间的差.例如:输入8729 ...
- YTU 2732:3798-Abs Problem
2732: 3798-Abs Problem 时间限制: 1 Sec 内存限制: 128 MB Special Judge 提交: 167 解决: 60 题目描述 Alice and Bob i ...
- codeforces 920 EFG 题解合集 ( Educational Codeforces Round 37 )
E. Connected Components? time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- 第四周 Leetcode 124. Binary Tree Maximum Path Sum (HARD)
124. Binary Tree Maximum Path Sum 题意:给定一个二叉树,每个节点有一个权值,寻找任意一个路径,使得权值和最大,只需返回权值和. 思路:对于每一个节点 首先考虑以这个节 ...
- 如何根据configure.ac和Makefile.am为开源代码产生当前平台的Makefile
1 2 3 4 5 6 7 8 9 //根据configure.in和Makefile.am生成makefile的步骤,基于UBUNTU 12.04 1.autoscan (可选) 2.aclocal ...