大家好,又见面了,我是你们的朋友全栈君。
基于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.该上源码了,应该没啥看不懂的吧
1 `timescale 1ns/1ns
2
3 module tb_sdram_top;
4
5 reg sclk ;
6 reg s_rst_n ;
7
8 //----------------------------------------------------------
9 wire sdram_clk ;
10 wire sdram_cke ;
11 wire sdram_cs_n ;
12 wire sdram_cas_n ;
13 wire sdram_ras_n ;
14 wire sdram_we_n ;
15 wire [1:0] sdram_bank ;
16 wire [12:0] sdram_addr ;
17 wire [1:0] sdram_dqm ;
18 wire [15:0] sdram_dq ;
19
20
21
22
23
24 initial begin
25 sclk = 1;
26 s_rst_n <= 0;
27 #100
28 s_rst_n <= 1;
29 end
30
31 always #10 sclk = ~sclk;
32
33
34
35 sdram_top sdram_top_inst(
36 //system signals
37 .sclk (sclk ),
38 .s_rst_n (s_rst_n ),
39 //SDRAM Interfaces
40 .sdram_clk (sdram_clk ),
41 .sdram_cke (sdram_cke ),
42 .sdram_cs_n (sdram_cs_n ),
43 .sdram_cas_n (sdram_cas_n ),
44 .sdram_ras_n (sdram_ras_n ),
45 .sdram_we_n (sdram_we_n ),
46 .sdram_bank (sdram_bank ),
47 .sdram_addr (sdram_addr ),
48 .sdram_dqm (sdram_dqm ),
49 .sdram_dq (sdram_dq )
50 );
51
52
53 sdram_model_plus sdram_model_plus_inst(
54 .Dq (sdram_dq ),
55 .Addr (sdram_addr ),
56 .Ba (sdram_bank ),
57 .Clk (sdram_clk ),
58 .Cke (sdram_cke ),
59 .Cs_n (sdram_cs_n ),
60 .Ras_n (sdram_ras_n ),
61 .Cas_n (sdram_cas_n ),
62 .We_n (sdram_we_n ),
63 .Dqm (sdram_dqm ),
64 .Debug (1'b1 )
65 );
66
67 endmodule
tb_sdram_top
1 module sdram_ini(
2 //systejm signal
3 input sclk ,
4 input s_rst_n ,
5 //others
6 output reg [3:0] cmd_reg ,
7 output wire [12:0] sdram_addr ,
8 output flag_ini_end
9 );
10
11 //==============================================================================\
12 //*********************Define Parameter and Internal Signal ********************
13 //==============================================================================/
14
15 localparam DELAY_200US = 10000 ;
16 //SDRAM Command
17 localparam NOP = 4'b0111 ;
18 localparam PRE = 4'b0010 ;
19 localparam AREF = 4'b0001 ;
20 localparam MSET = 4'b0000 ;
21
22 reg [13:0] cnt_200us ;
23 wire flag_200us ;
24 reg [3:0] cnt_cmd ;
25
26 //=============================================================================\
27 //********************** Main Code ***************************************
28 //=============================================================================/
29
30 always @(posedge sclk or negedge s_rst_n) begin
31 if(s_rst_n == 1'b0)
32 cnt_200us <= 14'd0;
33 else if (flag_200us == 1'b0)
34 cnt_200us <= cnt_200us + 1'b1;
35 end
36
37 always @(posedge sclk or negedge s_rst_n) begin
38 if(s_rst_n == 1'b0)
39 cnt_cmd <= 4'd0;
40 else if(flag_200us == 1'b1 && flag_ini_end == 1'b0)
41 cnt_cmd <= cnt_cmd + 1'b1;
42 end
43
44 //cmd_reg
45 always @(posedge sclk or negedge s_rst_n ) begin
46 if(s_rst_n == 1'b0)
47 cmd_reg <= NOP;
48 else if(flag_200us == 1'b1)
49 case(cnt_cmd)
50 0: cmd_reg <= PRE ;
51 1: cmd_reg <= AREF ;
52 4: cmd_reg <= AREF ;
53 9: cmd_reg <= MSET ;
54 default : cmd_reg <= NOP ;
55 endcase
56 end
57 assign flag_ini_end = (cnt_cmd >= 4'd10) ? 1'b1 : 1'b0;
58 assign sdram_addr = (cmd_reg == MSET) ? 13'b0_0000_0011_0010 : 13'b0_0100_0000_0000;
59 assign flag_200us = (cnt_200us >= DELAY_200US) ? 1'b1 : 1'b0;
60
61 endmodule
sdram_init
1 module sdram_top(
2 //system signals
3 input sclk ,
4 input s_rst_n ,
5 //SDRAM Interfaces
6 output wire sdram_clk ,
7 output wire sdram_cke ,
8 output wire sdram_cs_n ,
9 output wire sdram_cas_n ,
10 output wire sdram_ras_n ,
11 output wire sdram_we_n ,
12 output wire [1:0] sdram_bank ,
13 output wire [12:0] sdram_addr ,
14 output wire [1:0] sdram_dqm ,
15 inout [15:0] sdram_dq
16 );
17
18 //==============================================================================\
19 //*********************Define Parameter and Internal Signal ********************
20 //==============================================================================/
21 //init module
22 wire flag_ini_end ;
23 wire [3:0] init_cmd ;
24 wire [12:0] init_addr ;
25
26
27 //=============================================================================\
28 //********************** Main Code ***************************************
29 //=============================================================================/
30 assign sdram_cke = 1'b1;
31 assign sdram_addr = init_addr;
32 assign {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = init_cmd ;
33 assign sdram_dqm = 2'd0;
34 assign sdram_clk = ~sclk;
35
36
37 sdram_ini sdram_ini_inst(
38 //systejm signal
39 .sclk (sclk ),
40 .s_rst_n (s_rst_n ),
41 //others
42 .cmd_reg (init_cmd ),
43 .sdram_addr (init_addr ),
44 .flag_ini_end (flag_ini_end )
45 );
46
47
48 endmodule
sdram_top
这用了一个sdram仿真模型,堪文老师是128的,我的256的不能用,但是我改好了
1 /***************************************************************************************
2 作者: 李晟
3 2003-08-27 V0.1 李晟
4
5 添加内存模块倒空功能,在外部需要创建事件:sdram_r ,本SDRAM的内容将会按Bank 顺序damp out 至文件
6 sdram_data.txt 中
7 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××*/
8 //2004-03-04 陈乃奎 修改原程序中将BANK的数据转存入TXT文件的格式
9 //2004-03-16 陈乃奎 修改SDRAM 的初始化数据
10 //2004/04/06 陈乃奎 将SDRAM的操作命令以字符形式表示,以便用MODELSIM监视
11 //2004/04/19 陈乃奎 修改参数 parameter tAC = 8;
12 //2010/09/17 罗瑶 修改sdram的大小,数据位宽,dqm宽度;
13 /****************************************************************************************
14 *
15 * File Name: sdram_model.V
16 * Version: 0.0f
17 * Date: July 8th, 1999
18 * Model: BUS Functional
19 * Simulator: Model Technology (PC version 5.2e PE)
20 *
21 * Dependencies: None
22 *
23 * Author: Son P. Huynh
24 * Email: sphuynh@micron.com
25 * Phone: (208) 368-3825
26 * Company: Micron Technology, Inc.
27 * Model: sdram_model (1Meg x 16 x 4 Banks)
28 *
29 * Description: 64Mb SDRAM Verilog model
30 *
31 * Limitation: - Doesn't check for 4096 cycle refresh
32 *
33 * Note: - Set simulator resolution to "ps" accuracy
34 * - Set Debug = 0 to disable $display messages
35 *
36 * Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY
37 * WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY
38 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
39 * A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT.
40 *
41 * Copyright ?1998 Micron Semiconductor Products, Inc.
42 * All rights researved
43 *
44 * Rev Author Phone Date Changes
45 * ---- ---------------------------- ---------- ---------------------------------------
46 * 0.0f Son Huynh 208-368-3825 07/08/1999 - Fix tWR = 1 Clk + 7.5 ns (Auto)
47 * Micron Technology Inc. - Fix tWR = 15 ns (Manual)
48 * - Fix tRP (Autoprecharge to AutoRefresh)
49 *
50 * 0.0a Son Huynh 208-368-3825 05/13/1998 - First Release (from 64Mb rev 0.0e)
51 * Micron Technology Inc.
52 ****************************************************************************************/
53
54 `timescale 1ns / 100ps
55
56 module sdram_model_plus (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm,Debug);
57
58 parameter addr_bits = 13;
59 parameter data_bits = 16;
60 parameter col_bits = 9;
61 parameter mem_sizes = 4*1024*1024 -1;//1 Meg
62
63 inout [data_bits - 1 : 0] Dq;
64 input [addr_bits - 1 : 0] Addr;
65 input [1 : 0] Ba;
66 input Clk;
67 input Cke;
68 input Cs_n;
69 input Ras_n;
70 input Cas_n;
71 input We_n;
72 input [1 : 0] Dqm; //高低各8bit
73 //added by xzli
74 input Debug;
75
76 reg [data_bits - 1 : 0] Bank0 [0 : mem_sizes];//存储器类型数据
77 reg [data_bits - 1 : 0] Bank1 [0 : mem_sizes];
78 reg [data_bits - 1 : 0] Bank2 [0 : mem_sizes];
79 reg [data_bits - 1 : 0] Bank3 [0 : mem_sizes];
80
81 reg [1 : 0] Bank_addr [0 : 3]; // Bank Address Pipeline
82 reg [col_bits - 1 : 0] Col_addr [0 : 3]; // Column Address Pipeline
83 reg [3 : 0] Command [0 : 3]; // Command Operation Pipeline
84 reg [3 : 0] Dqm_reg0, Dqm_reg1; // DQM Operation Pipeline
85 reg [addr_bits - 1 : 0] B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr;
86
87 reg [addr_bits - 1 : 0] Mode_reg;
88 reg [data_bits - 1 : 0] Dq_reg, Dq_dqm;
89 reg [col_bits - 1 : 0] Col_temp, Burst_counter;
90
91 reg Act_b0, Act_b1, Act_b2, Act_b3; // Bank Activate
92 reg Pc_b0, Pc_b1, Pc_b2, Pc_b3; // Bank Precharge
93
94 reg [1 : 0] Bank_precharge [0 : 3]; // Precharge Command
95 reg A10_precharge [0 : 3]; // Addr[10] = 1 (All banks)
96 reg Auto_precharge [0 : 3]; // RW AutoPrecharge (Bank)
97 reg Read_precharge [0 : 3]; // R AutoPrecharge
98 reg Write_precharge [0 : 3]; // W AutoPrecharge
99 integer Count_precharge [0 : 3]; // RW AutoPrecharge (Counter)
100 reg RW_interrupt_read [0 : 3]; // RW Interrupt Read with Auto Precharge
101 reg RW_interrupt_write [0 : 3]; // RW Interrupt Write with Auto Precharge
102
103 reg Data_in_enable;
104 reg Data_out_enable;
105
106 reg [1 : 0] Bank, Previous_bank;
107 reg [addr_bits - 1 : 0] Row;
108 reg [col_bits - 1 : 0] Col, Col_brst;
109
110 // Internal system clock
111 reg CkeZ, Sys_clk;
112
113 reg [24:0] dd;
114
115 // Commands Decode
116 wire Active_enable = ~Cs_n & ~Ras_n & Cas_n & We_n;
117 wire Aref_enable = ~Cs_n & ~Ras_n & ~Cas_n & We_n;
118 wire Burst_term = ~Cs_n & Ras_n & Cas_n & ~We_n;
119 wire Mode_reg_enable = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n;
120 wire Prech_enable = ~Cs_n & ~Ras_n & Cas_n & ~We_n;
121 wire Read_enable = ~Cs_n & Ras_n & ~Cas_n & We_n;
122 wire Write_enable = ~Cs_n & Ras_n & ~Cas_n & ~We_n;
123
124 // Burst Length Decode
125 wire Burst_length_1 = ~Mode_reg[2] & ~Mode_reg[1] & ~Mode_reg[0];
126 wire Burst_length_2 = ~Mode_reg[2] & ~Mode_reg[1] & Mode_reg[0];
127 wire Burst_length_4 = ~Mode_reg[2] & Mode_reg[1] & ~Mode_reg[0];
128 wire Burst_length_8 = ~Mode_reg[2] & Mode_reg[1] & Mode_reg[0];
129
130 // CAS Latency Decode
131 wire Cas_latency_2 = ~Mode_reg[6] & Mode_reg[5] & ~Mode_reg[4];
132 wire Cas_latency_3 = ~Mode_reg[6] & Mode_reg[5] & Mode_reg[4];
133
134 // Write Burst Mode
135 wire Write_burst_mode = Mode_reg[9];
136
137 wire Debug; // Debug messages : 1 = On; 0 = Off
138 wire Dq_chk = Sys_clk & Data_in_enable; // Check setup/hold time for DQ
139
140 reg [31:0] mem_d;
141
142 event sdram_r,sdram_w,compare;
143
144
145
146
147 assign Dq = Dq_reg; // DQ buffer
148
149 // Commands Operation
150 `define ACT 0
151 `define NOP 1
152 `define READ 2
153 `define READ_A 3
154 `define WRITE 4
155 `define WRITE_A 5
156 `define PRECH 6
157 `define A_REF 7
158 `define BST 8
159 `define LMR 9
160
161 // // Timing Parameters for -75 (PC133) and CAS Latency = 2
162 // parameter tAC = 8; //test 6.5
163 // parameter tHZ = 7.0;
164 // parameter tOH = 2.7;
165 // parameter tMRD = 2.0; // 2 Clk Cycles
166 // parameter tRAS = 44.0;
167 // parameter tRC = 66.0;
168 // parameter tRCD = 20.0;
169 // parameter tRP = 20.0;
170 // parameter tRRD = 15.0;
171 // parameter tWRa = 7.5; // A2 Version - Auto precharge mode only (1 Clk + 7.5 ns)
172 // parameter tWRp = 0.0; // A2 Version - Precharge mode only (15 ns)
173
174 // Timing Parameters for -7 (PC143) and CAS Latency = 3
175 parameter tAC = 6.5; //test 6.5
176 parameter tHZ = 5.5;
177 parameter tOH = 2;
178 parameter tMRD = 2.0; // 2 Clk Cycles
179 parameter tRAS = 48.0;
180 parameter tRC = 70.0;
181 parameter tRCD = 20.0;
182 parameter tRP = 20.0;
183 parameter tRRD = 14.0;
184 parameter tWRa = 7.5; // A2 Version - Auto precharge mode only (1 Clk + 7.5 ns)
185 parameter tWRp = 0.0; // A2 Version - Precharge mode only (15 ns)
186
187 // Timing Check variable
188 integer MRD_chk;
189 integer WR_counter [0 : 3];
190 time WR_chk [0 : 3];
191 time RC_chk, RRD_chk;
192 time RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3;
193 time RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3;
194 time RP_chk0, RP_chk1, RP_chk2, RP_chk3;
195
196 integer test_file;
197
198 //*****display the command of the sdram**************************************
199
200 parameter Mode_Reg_Set =4'b0000;
201 parameter Auto_Refresh =4'b0001;
202 parameter Row_Active =4'b0011;
203 parameter Pre_Charge =4'b0010;
204 parameter PreCharge_All =4'b0010;
205 parameter Write =4'b0100;
206 parameter Write_Pre =4'b0100;
207 parameter Read =4'b0101;
208 parameter Read_Pre =4'b0101;
209 parameter Burst_Stop =4'b0110;
210 parameter Nop =4'b0111;
211 parameter Dsel =4'b1111;
212
213 wire [3:0] sdram_control;
214 reg cke_temp;
215 reg [8*13:1] sdram_command;
216
217 always@(posedge Clk)
218 cke_temp<=Cke;
219
220 assign sdram_control={Cs_n,Ras_n,Cas_n,We_n};
221
222 always@(sdram_control or cke_temp)
223 begin
224 case(sdram_control)
225 Mode_Reg_Set: sdram_command<="Mode_Reg_Set";
226 Auto_Refresh: sdram_command<="Auto_Refresh";
227 Row_Active: sdram_command<="Row_Active";
228 Pre_Charge: sdram_command<="Pre_Charge";
229 Burst_Stop: sdram_command<="Burst_Stop";
230 Dsel: sdram_command<="Dsel";
231
232 Write: if(cke_temp==1)
233 sdram_command<="Write";
234 else
235 sdram_command<="Write_suspend";
236
237 Read: if(cke_temp==1)
238 sdram_command<="Read";
239 else
240 sdram_command<="Read_suspend";
241
242 Nop: if(cke_temp==1)
243 sdram_command<="Nop";
244 else
245 sdram_command<="Self_refresh";
246
247 default: sdram_command<="Power_down";
248 endcase
249 end
250
251 //*****************************************************
252
253 initial
254 begin
255 //test_file=$fopen("test_file.txt");
256 end
257
258 initial
259 begin
260 Dq_reg = {data_bits{1'bz}};
261 {Data_in_enable, Data_out_enable} = 0;
262 {Act_b0, Act_b1, Act_b2, Act_b3} = 4'b0000;
263 {Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 4'b0000;
264 {WR_chk[0], WR_chk[1], WR_chk[2], WR_chk[3]} = 0;
265 {WR_counter[0], WR_counter[1], WR_counter[2], WR_counter[3]} = 0;
266 {RW_interrupt_read[0], RW_interrupt_read[1], RW_interrupt_read[2], RW_interrupt_read[3]} = 0;
267 {RW_interrupt_write[0], RW_interrupt_write[1], RW_interrupt_write[2], RW_interrupt_write[3]} = 0;
268 {MRD_chk, RC_chk, RRD_chk} = 0;
269 {RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3} = 0;
270 {RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3} = 0;
271 {RP_chk0, RP_chk1, RP_chk2, RP_chk3} = 0;
272 $timeformat (-9, 0, " ns", 12);
273 //$readmemh("bank0.txt", Bank0);
274 //$readmemh("bank1.txt", Bank1);
275 //$readmemh("bank2.txt", Bank2);
276 //$readmemh("bank3.txt", Bank3);
277 /*
278 for(dd=0;dd<=mem_sizes;dd=dd+1)
279 begin
280 Bank0[dd]=dd[data_bits - 1 : 0];
281 Bank1[dd]=dd[data_bits - 1 : 0]+1;
282 Bank2[dd]=dd[data_bits - 1 : 0]+2;
283 Bank3[dd]=dd[data_bits - 1 : 0]+3;
284 end
285 */
286 initial_sdram(0);
287 end
288
289 task initial_sdram;
290
291 input data_sign;
292 reg [3:0] data_sign;
293
294 for(dd=0;dd<=mem_sizes;dd=dd+1)
295 begin
296 mem_d = {data_sign,data_sign,data_sign,data_sign,data_sign,data_sign,data_sign,data_sign};
297 if(data_bits==16)
298 begin
299 Bank0[dd]=mem_d[15:0];
300 Bank1[dd]=mem_d[15:0];
301 Bank2[dd]=mem_d[15:0];
302 Bank3[dd]=mem_d[15:0];
303 end
304 else if(data_bits==32)
305 begin
306 Bank0[dd]=mem_d[31:0];
307 Bank1[dd]=mem_d[31:0];
308 Bank2[dd]=mem_d[31:0];
309 Bank3[dd]=mem_d[31:0];
310 end
311 end
312
313 endtask
314
315 // System clock generator
316 always
317 begin
318 @(posedge Clk)
319 begin
320 Sys_clk = CkeZ;
321 CkeZ = Cke;
322 end
323 @(negedge Clk)
324 begin
325 Sys_clk = 1'b0;
326 end
327 end
328
329 always @ (posedge Sys_clk) begin
330 // Internal Commamd Pipelined
331 Command[0] = Command[1];
332 Command[1] = Command[2];
333 Command[2] = Command[3];
334 Command[3] = `NOP;
335
336 Col_addr[0] = Col_addr[1];
337 Col_addr[1] = Col_addr[2];
338 Col_addr[2] = Col_addr[3];
339 Col_addr[3] = {col_bits{1'b0}};
340
341 Bank_addr[0] = Bank_addr[1];
342 Bank_addr[1] = Bank_addr[2];
343 Bank_addr[2] = Bank_addr[3];
344 Bank_addr[3] = 2'b0;
345
346 Bank_precharge[0] = Bank_precharge[1];
347 Bank_precharge[1] = Bank_precharge[2];
348 Bank_precharge[2] = Bank_precharge[3];
349 Bank_precharge[3] = 2'b0;
350
351 A10_precharge[0] = A10_precharge[1];
352 A10_precharge[1] = A10_precharge[2];
353 A10_precharge[2] = A10_precharge[3];
354 A10_precharge[3] = 1'b0;
355
356 // Dqm pipeline for Read
357 Dqm_reg0 = Dqm_reg1;
358 Dqm_reg1 = Dqm;
359
360 // Read or Write with Auto Precharge Counter
361 if (Auto_precharge[0] == 1'b1) begin
362 Count_precharge[0] = Count_precharge[0] + 1;
363 end
364 if (Auto_precharge[1] == 1'b1) begin
365 Count_precharge[1] = Count_precharge[1] + 1;
366 end
367 if (Auto_precharge[2] == 1'b1) begin
368 Count_precharge[2] = Count_precharge[2] + 1;
369 end
370 if (Auto_precharge[3] == 1'b1) begin
371 Count_precharge[3] = Count_precharge[3] + 1;
372 end
373
374 // tMRD Counter
375 MRD_chk = MRD_chk + 1;
376
377 // tWR Counter for Write
378 WR_counter[0] = WR_counter[0] + 1;
379 WR_counter[1] = WR_counter[1] + 1;
380 WR_counter[2] = WR_counter[2] + 1;
381 WR_counter[3] = WR_counter[3] + 1;
382
383 // Auto Refresh
384 if (Aref_enable == 1'b1) begin
385 if (Debug) $display ("at time %t AREF : Auto Refresh", $time);
386 // Auto Refresh to Auto Refresh
387 if (($time - RC_chk < tRC)&&Debug) begin
388 $display ("at time %t ERROR: tRC violation during Auto Refresh", $time);
389 end
390 // Precharge to Auto Refresh
391 if (($time - RP_chk0 < tRP || $time - RP_chk1 < tRP || $time - RP_chk2 < tRP || $time - RP_chk3 < tRP)&&Debug) begin
392 $display ("at time %t ERROR: tRP violation during Auto Refresh", $time);
393 end
394 // Precharge to Refresh
395 if (Pc_b0 == 1'b0 || Pc_b1 == 1'b0 || Pc_b2 == 1'b0 || Pc_b3 == 1'b0) begin
396 $display ("at time %t ERROR: All banks must be Precharge before Auto Refresh", $time);
397 end
398 // Record Current tRC time
399 RC_chk = $time;
400 end
401
402 // Load Mode Register
403 if (Mode_reg_enable == 1'b1) begin
404 // Decode CAS Latency, Burst Length, Burst Type, and Write Burst Mode
405 if (Pc_b0 == 1'b1 && Pc_b1 == 1'b1 && Pc_b2 == 1'b1 && Pc_b3 == 1'b1) begin
406 Mode_reg = Addr;
407 if (Debug) begin
408 $display ("at time %t LMR : Load Mode Register", $time);
409 // CAS Latency
410 if (Addr[6 : 4] == 3'b010)
411 $display (" CAS Latency = 2");
412 else if (Addr[6 : 4] == 3'b011)
413 $display (" CAS Latency = 3");
414 else
415 $display (" CAS Latency = Reserved");
416 // Burst Length
417 if (Addr[2 : 0] == 3'b000)
418 $display (" Burst Length = 1");
419 else if (Addr[2 : 0] == 3'b001)
420 $display (" Burst Length = 2");
421 else if (Addr[2 : 0] == 3'b010)
422 $display (" Burst Length = 4");
423 else if (Addr[2 : 0] == 3'b011)
424 $display (" Burst Length = 8");
425 else if (Addr[3 : 0] == 4'b0111)
426 $display (" Burst Length = Full");
427 else
428 $display (" Burst Length = Reserved");
429 // Burst Type
430 if (Addr[3] == 1'b0)
431 $display (" Burst Type = Sequential");
432 else if (Addr[3] == 1'b1)
433 $display (" Burst Type = Interleaved");
434 else
435 $display (" Burst Type = Reserved");
436 // Write Burst Mode
437 if (Addr[9] == 1'b0)
438 $display (" Write Burst Mode = Programmed Burst Length");
439 else if (Addr[9] == 1'b1)
440 $display (" Write Burst Mode = Single Location Access");
441 else
442 $display (" Write Burst Mode = Reserved");
443 end
444 end else begin
445 $display ("at time %t ERROR: all banks must be Precharge before Load Mode Register", $time);
446 end
447 // REF to LMR
448 if ($time - RC_chk < tRC) begin
449 $display ("at time %t ERROR: tRC violation during Load Mode Register", $time);
450 end
451 // LMR to LMR
452 if (MRD_chk < tMRD) begin
453 $display ("at time %t ERROR: tMRD violation during Load Mode Register", $time);
454 end
455 MRD_chk = 0;
456 end
457
458 // Active Block (Latch Bank Address and Row Address)
459 if (Active_enable == 1'b1) begin
460 if (Ba == 2'b00 && Pc_b0 == 1'b1) begin
461 {Act_b0, Pc_b0} = 2'b10;
462 B0_row_addr = Addr [addr_bits - 1 : 0];
463 RCD_chk0 = $time;
464 RAS_chk0 = $time;
465 if (Debug) $display ("at time %t ACT : Bank = 0 Row = %d", $time, Addr);
466 // Precharge to Activate Bank 0
467 if ($time - RP_chk0 < tRP) begin
468 $display ("at time %t ERROR: tRP violation during Activate bank 0", $time);
469 end
470 end else if (Ba == 2'b01 && Pc_b1 == 1'b1) begin
471 {Act_b1, Pc_b1} = 2'b10;
472 B1_row_addr = Addr [addr_bits - 1 : 0];
473 RCD_chk1 = $time;
474 RAS_chk1 = $time;
475 if (Debug) $display ("at time %t ACT : Bank = 1 Row = %d", $time, Addr);
476 // Precharge to Activate Bank 1
477 if ($time - RP_chk1 < tRP) begin
478 $display ("at time %t ERROR: tRP violation during Activate bank 1", $time);
479 end
480 end else if (Ba == 2'b10 && Pc_b2 == 1'b1) begin
481 {Act_b2, Pc_b2} = 2'b10;
482 B2_row_addr = Addr [addr_bits - 1 : 0];
483 RCD_chk2 = $time;
484 RAS_chk2 = $time;
485 if (Debug) $display ("at time %t ACT : Bank = 2 Row = %d", $time, Addr);
486 // Precharge to Activate Bank 2
487 if ($time - RP_chk2 < tRP) begin
488 $display ("at time %t ERROR: tRP violation during Activate bank 2", $time);
489 end
490 end else if (Ba == 2'b11 && Pc_b3 == 1'b1) begin
491 {Act_b3, Pc_b3} = 2'b10;
492 B3_row_addr = Addr [addr_bits - 1 : 0];
493 RCD_chk3 = $time;
494 RAS_chk3 = $time;
495 if (Debug) $display ("at time %t ACT : Bank = 3 Row = %d", $time, Addr);
496 // Precharge to Activate Bank 3
497 if ($time - RP_chk3 < tRP) begin
498 $display ("at time %t ERROR: tRP violation during Activate bank 3", $time);
499 end
500 end else if (Ba == 2'b00 && Pc_b0 == 1'b0) begin
501 $display ("at time %t ERROR: Bank 0 is not Precharged.", $time);
502 end else if (Ba == 2'b01 && Pc_b1 == 1'b0) begin
503 $display ("at time %t ERROR: Bank 1 is not Precharged.", $time);
504 end else if (Ba == 2'b10 && Pc_b2 == 1'b0) begin
505 $display ("at time %t ERROR: Bank 2 is not Precharged.", $time);
506 end else if (Ba == 2'b11 && Pc_b3 == 1'b0) begin
507 $display ("at time %t ERROR: Bank 3 is not Precharged.", $time);
508 end
509 // Active Bank A to Active Bank B
510 if ((Previous_bank != Ba) && ($time - RRD_chk < tRRD)) begin
511 $display ("at time %t ERROR: tRRD violation during Activate bank = %d", $time, Ba);
512 end
513 // Load Mode Register to Active
514 if (MRD_chk < tMRD ) begin
515 $display ("at time %t ERROR: tMRD violation during Activate bank = %d", $time, Ba);
516 end
517 // Auto Refresh to Activate
518 if (($time - RC_chk < tRC)&&Debug) begin
519 $display ("at time %t ERROR: tRC violation during Activate bank = %d", $time, Ba);
520 end
521 // Record variables for checking violation
522 RRD_chk = $time;
523 Previous_bank = Ba;
524 end
525
526 // Precharge Block
527 if (Prech_enable == 1'b1) begin
528 if (Addr[10] == 1'b1) begin
529 {Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 4'b1111;
530 {Act_b0, Act_b1, Act_b2, Act_b3} = 4'b0000;
531 RP_chk0 = $time;
532 RP_chk1 = $time;
533 RP_chk2 = $time;
534 RP_chk3 = $time;
535 if (Debug) $display ("at time %t PRE : Bank = ALL",$time);
536 // Activate to Precharge all banks
537 if (($time - RAS_chk0 < tRAS) || ($time - RAS_chk1 < tRAS) ||
538 ($time - RAS_chk2 < tRAS) || ($time - RAS_chk3 < tRAS)) begin
539 $display ("at time %t ERROR: tRAS violation during Precharge all bank", $time);
540 end
541 // tWR violation check for write
542 if (($time - WR_chk[0] < tWRp) || ($time - WR_chk[1] < tWRp) ||
543 ($time - WR_chk[2] < tWRp) || ($time - WR_chk[3] < tWRp)) begin
544 $display ("at time %t ERROR: tWR violation during Precharge all bank", $time);
545 end
546 end else if (Addr[10] == 1'b0) begin
547 if (Ba == 2'b00) begin
548 {Pc_b0, Act_b0} = 2'b10;
549 RP_chk0 = $time;
550 if (Debug) $display ("at time %t PRE : Bank = 0",$time);
551 // Activate to Precharge Bank 0
552 if ($time - RAS_chk0 < tRAS) begin
553 $display ("at time %t ERROR: tRAS violation during Precharge bank 0", $time);
554 end
555 end else if (Ba == 2'b01) begin
556 {Pc_b1, Act_b1} = 2'b10;
557 RP_chk1 = $time;
558 if (Debug) $display ("at time %t PRE : Bank = 1",$time);
559 // Activate to Precharge Bank 1
560 if ($time - RAS_chk1 < tRAS) begin
561 $display ("at time %t ERROR: tRAS violation during Precharge bank 1", $time);
562 end
563 end else if (Ba == 2'b10) begin
564 {Pc_b2, Act_b2} = 2'b10;
565 RP_chk2 = $time;
566 if (Debug) $display ("at time %t PRE : Bank = 2",$time);
567 // Activate to Precharge Bank 2
568 if ($time - RAS_chk2 < tRAS) begin
569 $display ("at time %t ERROR: tRAS violation during Precharge bank 2", $time);
570 end
571 end else if (Ba == 2'b11) begin
572 {Pc_b3, Act_b3} = 2'b10;
573 RP_chk3 = $time;
574 if (Debug) $display ("at time %t PRE : Bank = 3",$time);
575 // Activate to Precharge Bank 3
576 if ($time - RAS_chk3 < tRAS) begin
577 $display ("at time %t ERROR: tRAS violation during Precharge bank 3", $time);
578 end
579 end
580 // tWR violation check for write
581 if ($time - WR_chk[Ba] < tWRp) begin
582 $display ("at time %t ERROR: tWR violation during Precharge bank %d", $time, Ba);
583 end
584 end
585 // Terminate a Write Immediately (if same bank or all banks)
586 if (Data_in_enable == 1'b1 && (Bank == Ba || Addr[10] == 1'b1)) begin
587 Data_in_enable = 1'b0;
588 end
589 // Precharge Command Pipeline for Read
590 if (Cas_latency_3 == 1'b1) begin
591 Command[2] = `PRECH;
592 Bank_precharge[2] = Ba;
593 A10_precharge[2] = Addr[10];
594 end else if (Cas_latency_2 == 1'b1) begin
595 Command[1] = `PRECH;
596 Bank_precharge[1] = Ba;
597 A10_precharge[1] = Addr[10];
598 end
599 end
600
601 // Burst terminate
602 if (Burst_term == 1'b1) begin
603 // Terminate a Write Immediately
604 if (Data_in_enable == 1'b1) begin
605 Data_in_enable = 1'b0;
606 end
607 // Terminate a Read Depend on CAS Latency
608 if (Cas_latency_3 == 1'b1) begin
609 Command[2] = `BST;
610 end else if (Cas_latency_2 == 1'b1) begin
611 Command[1] = `BST;
612 end
613 if (Debug) $display ("at time %t BST : Burst Terminate",$time);
614 end
615
616 // Read, Write, Column Latch
617 if (Read_enable == 1'b1 || Write_enable == 1'b1) begin
618 // Check to see if bank is open (ACT)
619 if ((Ba == 2'b00 && Pc_b0 == 1'b1) || (Ba == 2'b01 && Pc_b1 == 1'b1) ||
620 (Ba == 2'b10 && Pc_b2 == 1'b1) || (Ba == 2'b11 && Pc_b3 == 1'b1)) begin
621 $display("at time %t ERROR: Cannot Read or Write - Bank %d is not Activated", $time, Ba);
622 end
623 // Activate to Read or Write
624 if ((Ba == 2'b00) && ($time - RCD_chk0 < tRCD))
625 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 0", $time);
626 if ((Ba == 2'b01) && ($time - RCD_chk1 < tRCD))
627 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 1", $time);
628 if ((Ba == 2'b10) && ($time - RCD_chk2 < tRCD))
629 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 2", $time);
630 if ((Ba == 2'b11) && ($time - RCD_chk3 < tRCD))
631 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 3", $time);
632 // Read Command
633 if (Read_enable == 1'b1) begin
634 // CAS Latency pipeline
635 if (Cas_latency_3 == 1'b1) begin
636 if (Addr[10] == 1'b1) begin
637 Command[2] = `READ_A;
638 end else begin
639 Command[2] = `READ;
640 end
641 Col_addr[2] = Addr;
642 Bank_addr[2] = Ba;
643 end else if (Cas_latency_2 == 1'b1) begin
644 if (Addr[10] == 1'b1) begin
645 Command[1] = `READ_A;
646 end else begin
647 Command[1] = `READ;
648 end
649 Col_addr[1] = Addr;
650 Bank_addr[1] = Ba;
651 end
652
653 // Read interrupt Write (terminate Write immediately)
654 if (Data_in_enable == 1'b1) begin
655 Data_in_enable = 1'b0;
656 end
657
658 // Write Command
659 end else if (Write_enable == 1'b1) begin
660 if (Addr[10] == 1'b1) begin
661 Command[0] = `WRITE_A;
662 end else begin
663 Command[0] = `WRITE;
664 end
665 Col_addr[0] = Addr;
666 Bank_addr[0] = Ba;
667
668 // Write interrupt Write (terminate Write immediately)
669 if (Data_in_enable == 1'b1) begin
670 Data_in_enable = 1'b0;
671 end
672
673 // Write interrupt Read (terminate Read immediately)
674 if (Data_out_enable == 1'b1) begin
675 Data_out_enable = 1'b0;
676 end
677 end
678
679 // Interrupting a Write with Autoprecharge
680 if (Auto_precharge[Bank] == 1'b1 && Write_precharge[Bank] == 1'b1) begin
681 RW_interrupt_write[Bank] = 1'b1;
682 if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Write Bank %d with Autoprecharge", $time, Ba, Bank);
683 end
684
685 // Interrupting a Read with Autoprecharge
686 if (Auto_precharge[Bank] == 1'b1 && Read_precharge[Bank] == 1'b1) begin
687 RW_interrupt_read[Bank] = 1'b1;
688 if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Read Bank %d with Autoprecharge", $time, Ba, Bank);
689 end
690
691 // Read or Write with Auto Precharge
692 if (Addr[10] == 1'b1) begin
693 Auto_precharge[Ba] = 1'b1;
694 Count_precharge[Ba] = 0;
695 if (Read_enable == 1'b1) begin
696 Read_precharge[Ba] = 1'b1;
697 end else if (Write_enable == 1'b1) begin
698 Write_precharge[Ba] = 1'b1;
699 end
700 end
701 end
702
703 // Read with Auto Precharge Calculation
704 // The device start internal precharge:
705 // 1. CAS Latency - 1 cycles before last burst
706 // and 2. Meet minimum tRAS requirement
707 // or 3. Interrupt by a Read or Write (with or without AutoPrecharge)
708 if ((Auto_precharge[0] == 1'b1) && (Read_precharge[0] == 1'b1)) begin
709 if ((($time - RAS_chk0 >= tRAS) && // Case 2
710 ((Burst_length_1 == 1'b1 && Count_precharge[0] >= 1) || // Case 1
711 (Burst_length_2 == 1'b1 && Count_precharge[0] >= 2) ||
712 (Burst_length_4 == 1'b1 && Count_precharge[0] >= 4) ||
713 (Burst_length_8 == 1'b1 && Count_precharge[0] >= 8))) ||
714 (RW_interrupt_read[0] == 1'b1)) begin // Case 3
715 Pc_b0 = 1'b1;
716 Act_b0 = 1'b0;
717 RP_chk0 = $time;
718 Auto_precharge[0] = 1'b0;
719 Read_precharge[0] = 1'b0;
720 RW_interrupt_read[0] = 1'b0;
721 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time);
722 end
723 end
724 if ((Auto_precharge[1] == 1'b1) && (Read_precharge[1] == 1'b1)) begin
725 if ((($time - RAS_chk1 >= tRAS) &&
726 ((Burst_length_1 == 1'b1 && Count_precharge[1] >= 1) ||
727 (Burst_length_2 == 1'b1 && Count_precharge[1] >= 2) ||
728 (Burst_length_4 == 1'b1 && Count_precharge[1] >= 4) ||
729 (Burst_length_8 == 1'b1 && Count_precharge[1] >= 8))) ||
730 (RW_interrupt_read[1] == 1'b1)) begin
731 Pc_b1 = 1'b1;
732 Act_b1 = 1'b0;
733 RP_chk1 = $time;
734 Auto_precharge[1] = 1'b0;
735 Read_precharge[1] = 1'b0;
736 RW_interrupt_read[1] = 1'b0;
737 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time);
738 end
739 end
740 if ((Auto_precharge[2] == 1'b1) && (Read_precharge[2] == 1'b1)) begin
741 if ((($time - RAS_chk2 >= tRAS) &&
742 ((Burst_length_1 == 1'b1 && Count_precharge[2] >= 1) ||
743 (Burst_length_2 == 1'b1 && Count_precharge[2] >= 2) ||
744 (Burst_length_4 == 1'b1 && Count_precharge[2] >= 4) ||
745 (Burst_length_8 == 1'b1 && Count_precharge[2] >= 8))) ||
746 (RW_interrupt_read[2] == 1'b1)) begin
747 Pc_b2 = 1'b1;
748 Act_b2 = 1'b0;
749 RP_chk2 = $time;
750 Auto_precharge[2] = 1'b0;
751 Read_precharge[2] = 1'b0;
752 RW_interrupt_read[2] = 1'b0;
753 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time);
754 end
755 end
756 if ((Auto_precharge[3] == 1'b1) && (Read_precharge[3] == 1'b1)) begin
757 if ((($time - RAS_chk3 >= tRAS) &&
758 ((Burst_length_1 == 1'b1 && Count_precharge[3] >= 1) ||
759 (Burst_length_2 == 1'b1 && Count_precharge[3] >= 2) ||
760 (Burst_length_4 == 1'b1 && Count_precharge[3] >= 4) ||
761 (Burst_length_8 == 1'b1 && Count_precharge[3] >= 8))) ||
762 (RW_interrupt_read[3] == 1'b1)) begin
763 Pc_b3 = 1'b1;
764 Act_b3 = 1'b0;
765 RP_chk3 = $time;
766 Auto_precharge[3] = 1'b0;
767 Read_precharge[3] = 1'b0;
768 RW_interrupt_read[3] = 1'b0;
769 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time);
770 end
771 end
772
773 // Internal Precharge or Bst
774 if (Command[0] == `PRECH) begin // Precharge terminate a read with same bank or all banks
775 if (Bank_precharge[0] == Bank || A10_precharge[0] == 1'b1) begin
776 if (Data_out_enable == 1'b1) begin
777 Data_out_enable = 1'b0;
778 end
779 end
780 end else if (Command[0] == `BST) begin // BST terminate a read to current bank
781 if (Data_out_enable == 1'b1) begin
782 Data_out_enable = 1'b0;
783 end
784 end
785
786 if (Data_out_enable == 1'b0) begin
787 Dq_reg <= #tOH {data_bits{1'bz}};
788 end
789
790 // Detect Read or Write command
791 if (Command[0] == `READ || Command[0] == `READ_A) begin
792 Bank = Bank_addr[0];
793 Col = Col_addr[0];
794 Col_brst = Col_addr[0];
795 if (Bank_addr[0] == 2'b00) begin
796 Row = B0_row_addr;
797 end else if (Bank_addr[0] == 2'b01) begin
798 Row = B1_row_addr;
799 end else if (Bank_addr[0] == 2'b10) begin
800 Row = B2_row_addr;
801 end else if (Bank_addr[0] == 2'b11) begin
802 Row = B3_row_addr;
803 end
804 Burst_counter = 0;
805 Data_in_enable = 1'b0;
806 Data_out_enable = 1'b1;
807 end else if (Command[0] == `WRITE || Command[0] == `WRITE_A) begin
808 Bank = Bank_addr[0];
809 Col = Col_addr[0];
810 Col_brst = Col_addr[0];
811 if (Bank_addr[0] == 2'b00) begin
812 Row = B0_row_addr;
813 end else if (Bank_addr[0] == 2'b01) begin
814 Row = B1_row_addr;
815 end else if (Bank_addr[0] == 2'b10) begin
816 Row = B2_row_addr;
817 end else if (Bank_addr[0] == 2'b11) begin
818 Row = B3_row_addr;
819 end
820 Burst_counter = 0;
821 Data_in_enable = 1'b1;
822 Data_out_enable = 1'b0;
823 end
824
825 // DQ buffer (Driver/Receiver)
826 if (Data_in_enable == 1'b1) begin // Writing Data to Memory
827 // Array buffer
828 if (Bank == 2'b00) Dq_dqm [data_bits - 1 : 0] = Bank0 [{Row, Col}];
829 if (Bank == 2'b01) Dq_dqm [data_bits - 1 : 0] = Bank1 [{Row, Col}];
830 if (Bank == 2'b10) Dq_dqm [data_bits - 1 : 0] = Bank2 [{Row, Col}];
831 if (Bank == 2'b11) Dq_dqm [data_bits - 1 : 0] = Bank3 [{Row, Col}];
832 // Dqm operation
833 if (Dqm[0] == 1'b0) Dq_dqm [ 7 : 0] = Dq [ 7 : 0];
834 if (Dqm[1] == 1'b0) Dq_dqm [15 : 8] = Dq [15 : 8];
835 //if (Dqm[2] == 1'b0) Dq_dqm [23 : 16] = Dq [23 : 16];
836 // if (Dqm[3] == 1'b0) Dq_dqm [31 : 24] = Dq [31 : 24];
837 // Write to memory
838 if (Bank == 2'b00) Bank0 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0];
839 if (Bank == 2'b01) Bank1 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0];
840 if (Bank == 2'b10) Bank2 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0];
841 if (Bank == 2'b11) Bank3 [{Row, Col}] = Dq_dqm [data_bits - 1 : 0];
842 if (Bank == 2'b11 && Row==10'h3 && Col[7:4]==4'h4)
843 $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
844 //$fdisplay(test_file,"bank:%h row:%h col:%h write:%h",Bank,Row,Col,Dq_dqm);
845 // Output result
846 if (Dqm == 4'b1111) begin
847 if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
848 end else begin
849 if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = %d, Dqm = %b", $time, Bank, Row, Col, Dq_dqm, Dqm);
850 // Record tWR time and reset counter
851 WR_chk [Bank] = $time;
852 WR_counter [Bank] = 0;
853 end
854 // Advance burst counter subroutine
855 #tHZ Burst;
856 end else if (Data_out_enable == 1'b1) begin // Reading Data from Memory
857 //$display("%h , %h, %h",Bank0,Row,Col);
858 // Array buffer
859 if (Bank == 2'b00) Dq_dqm [data_bits - 1 : 0] = Bank0 [{Row, Col}];
860 if (Bank == 2'b01) Dq_dqm [data_bits - 1 : 0] = Bank1 [{Row, Col}];
861 if (Bank == 2'b10) Dq_dqm [data_bits - 1 : 0] = Bank2 [{Row, Col}];
862 if (Bank == 2'b11) Dq_dqm [data_bits - 1 : 0] = Bank3 [{Row, Col}];
863
864 // Dqm operation
865 if (Dqm_reg0[0] == 1'b1) Dq_dqm [ 7 : 0] = 8'bz;
866 if (Dqm_reg0[1] == 1'b1) Dq_dqm [15 : 8] = 8'bz;
867 if (Dqm_reg0[2] == 1'b1) Dq_dqm [23 : 16] = 8'bz;
868 if (Dqm_reg0[3] == 1'b1) Dq_dqm [31 : 24] = 8'bz;
869 // Display result
870 Dq_reg [data_bits - 1 : 0] = #tAC Dq_dqm [data_bits - 1 : 0];
871 if (Dqm_reg0 == 4'b1111) begin
872 if (Debug) $display("at time %t READ : Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
873 end else begin
874 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);
875 end
876 // Advance burst counter subroutine
877 Burst;
878 end
879 end
880
881 // Write with Auto Precharge Calculation
882 // The device start internal precharge:
883 // 1. tWR Clock after last burst
884 // and 2. Meet minimum tRAS requirement
885 // or 3. Interrupt by a Read or Write (with or without AutoPrecharge)
886 always @ (WR_counter[0]) begin
887 if ((Auto_precharge[0] == 1'b1) && (Write_precharge[0] == 1'b1)) begin
888 if ((($time - RAS_chk0 >= tRAS) && // Case 2
889 (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [0] >= 1) || // Case 1
890 (Burst_length_2 == 1'b1 && Count_precharge [0] >= 2) ||
891 (Burst_length_4 == 1'b1 && Count_precharge [0] >= 4) ||
892 (Burst_length_8 == 1'b1 && Count_precharge [0] >= 8))) ||
893 (RW_interrupt_write[0] == 1'b1 && WR_counter[0] >= 2)) begin // Case 3 (stop count when interrupt)
894 Auto_precharge[0] = 1'b0;
895 Write_precharge[0] = 1'b0;
896 RW_interrupt_write[0] = 1'b0;
897 #tWRa; // Wait for tWR
898 Pc_b0 = 1'b1;
899 Act_b0 = 1'b0;
900 RP_chk0 = $time;
901 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time);
902 end
903 end
904 end
905 always @ (WR_counter[1]) begin
906 if ((Auto_precharge[1] == 1'b1) && (Write_precharge[1] == 1'b1)) begin
907 if ((($time - RAS_chk1 >= tRAS) &&
908 (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [1] >= 1) ||
909 (Burst_length_2 == 1'b1 && Count_precharge [1] >= 2) ||
910 (Burst_length_4 == 1'b1 && Count_precharge [1] >= 4) ||
911 (Burst_length_8 == 1'b1 && Count_precharge [1] >= 8))) ||
912 (RW_interrupt_write[1] == 1'b1 && WR_counter[1] >= 2)) begin
913 Auto_precharge[1] = 1'b0;
914 Write_precharge[1] = 1'b0;
915 RW_interrupt_write[1] = 1'b0;
916 #tWRa; // Wait for tWR
917 Pc_b1 = 1'b1;
918 Act_b1 = 1'b0;
919 RP_chk1 = $time;
920 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time);
921 end
922 end
923 end
924 always @ (WR_counter[2]) begin
925 if ((Auto_precharge[2] == 1'b1) && (Write_precharge[2] == 1'b1)) begin
926 if ((($time - RAS_chk2 >= tRAS) &&
927 (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [2] >= 1) ||
928 (Burst_length_2 == 1'b1 && Count_precharge [2] >= 2) ||
929 (Burst_length_4 == 1'b1 && Count_precharge [2] >= 4) ||
930 (Burst_length_8 == 1'b1 && Count_precharge [2] >= 8))) ||
931 (RW_interrupt_write[2] == 1'b1 && WR_counter[2] >= 2)) begin
932 Auto_precharge[2] = 1'b0;
933 Write_precharge[2] = 1'b0;
934 RW_interrupt_write[2] = 1'b0;
935 #tWRa; // Wait for tWR
936 Pc_b2 = 1'b1;
937 Act_b2 = 1'b0;
938 RP_chk2 = $time;
939 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time);
940 end
941 end
942 end
943 always @ (WR_counter[3]) begin
944 if ((Auto_precharge[3] == 1'b1) && (Write_precharge[3] == 1'b1)) begin
945 if ((($time - RAS_chk3 >= tRAS) &&
946 (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [3] >= 1) ||
947 (Burst_length_2 == 1'b1 && Count_precharge [3] >= 2) ||
948 (Burst_length_4 == 1'b1 && Count_precharge [3] >= 4) ||
949 (Burst_length_8 == 1'b1 && Count_precharge [3] >= 8))) ||
950 (RW_interrupt_write[3] == 1'b1 && WR_counter[3] >= 2)) begin
951 Auto_precharge[3] = 1'b0;
952 Write_precharge[3] = 1'b0;
953 RW_interrupt_write[3] = 1'b0;
954 #tWRa; // Wait for tWR
955 Pc_b3 = 1'b1;
956 Act_b3 = 1'b0;
957 RP_chk3 = $time;
958 if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time);
959 end
960 end
961 end
962
963 task Burst;
964 begin
965 // Advance Burst Counter
966 Burst_counter = Burst_counter + 1;
967
968 // Burst Type
969 if (Mode_reg[3] == 1'b0) begin // Sequential Burst
970 Col_temp = Col + 1;
971 end else if (Mode_reg[3] == 1'b1) begin // Interleaved Burst
972 Col_temp[2] = Burst_counter[2] ^ Col_brst[2];
973 Col_temp[1] = Burst_counter[1] ^ Col_brst[1];
974 Col_temp[0] = Burst_counter[0] ^ Col_brst[0];
975 end
976
977 // Burst Length
978 if (Burst_length_2) begin // Burst Length = 2
979 Col [0] = Col_temp [0];
980 end else if (Burst_length_4) begin // Burst Length = 4
981 Col [1 : 0] = Col_temp [1 : 0];
982 end else if (Burst_length_8) begin // Burst Length = 8
983 Col [2 : 0] = Col_temp [2 : 0];
984 end else begin // Burst Length = FULL
985 Col = Col_temp;
986 end
987
988 // Burst Read Single Write
989 if (Write_burst_mode == 1'b1) begin
990 Data_in_enable = 1'b0;
991 end
992
993 // Data Counter
994 if (Burst_length_1 == 1'b1) begin
995 if (Burst_counter >= 1) begin
996 Data_in_enable = 1'b0;
997 Data_out_enable = 1'b0;
998 end
999 end else if (Burst_length_2 == 1'b1) begin
1000 if (Burst_counter >= 2) begin
1001 Data_in_enable = 1'b0;
1002 Data_out_enable = 1'b0;
1003 end
1004 end else if (Burst_length_4 == 1'b1) begin
1005 if (Burst_counter >= 4) begin
1006 Data_in_enable = 1'b0;
1007 Data_out_enable = 1'b0;
1008 end
1009 end else if (Burst_length_8 == 1'b1) begin
1010 if (Burst_counter >= 8) begin
1011 Data_in_enable = 1'b0;
1012 Data_out_enable = 1'b0;
1013 end
1014 end
1015 end
1016 endtask
1017
1018 //**********************将SDRAM内的数据直接输出到外部文件*******************************//
1019
1020 /*
1021 integer sdram_data,ind;
1022
1023
1024 always@(sdram_r)
1025 begin
1026 sdram_data=$fopen("sdram_data.txt");
1027 $display("Sdram dampout begin ",sdram_data);
1028 // $fdisplay(sdram_data,"Bank0:");
1029 for(ind=0;ind<=mem_sizes;ind=ind+1)
1030 $fdisplay(sdram_data,"%h %b",ind,Bank0[ind]);
1031 // $fdisplay(sdram_data,"Bank1:");
1032 for(ind=0;ind<=mem_sizes;ind=ind+1)
1033 $fdisplay(sdram_data,"%h %b",ind,Bank1[ind]);
1034 // $fdisplay(sdram_data,"Bank2:");
1035 for(ind=0;ind<=mem_sizes;ind=ind+1)
1036 $fdisplay(sdram_data,"%h %b",ind,Bank2[ind]);
1037 // $fdisplay(sdram_data,"Bank3:");
1038 for(ind=0;ind<=mem_sizes;ind=ind+1)
1039 $fdisplay(sdram_data,"%h %b",ind,Bank3[ind]);
1040
1041 $fclose("sdram_data.txt");
1042 //->compare;
1043 end
1044 */
1045 integer sdram_data,sdram_mem;
1046 reg [24:0] aa,cc;
1047 reg [24:0] bb,ee;
1048
1049 always@(sdram_r)
1050 begin
1051 $display("Sdram dampout begin ",$realtime);
1052 sdram_data=$fopen("sdram_data.txt");
1053 for(aa=0;aa<4*(mem_sizes+1);aa=aa+1)
1054 begin
1055 bb=aa[18:0];
1056 if(aa<=mem_sizes)
1057 $fdisplay(sdram_data,"%0d %0h",aa,Bank0[bb]);
1058 else if(aa<=2*mem_sizes+1)
1059 $fdisplay(sdram_data,"%0d %0h",aa,Bank1[bb]);
1060 else if(aa<=3*mem_sizes+2)
1061 $fdisplay(sdram_data,"%0d %0h",aa,Bank2[bb]);
1062 else
1063 $fdisplay(sdram_data,"%0d %0h",aa,Bank3[bb]);
1064 end
1065 $fclose("sdram_data.txt");
1066
1067 sdram_mem=$fopen("sdram_mem.txt");
1068 for(cc=0;cc<4*(mem_sizes+1);cc=cc+1)
1069 begin
1070 ee=cc[18:0];
1071 if(cc<=mem_sizes)
1072 $fdisplay(sdram_mem,"%0h",Bank0[ee]);
1073 else if(cc<=2*mem_sizes+1)
1074 $fdisplay(sdram_mem,"%0h",Bank1[ee]);
1075 else if(cc<=3*mem_sizes+2)
1076 $fdisplay(sdram_mem,"%0h",Bank2[ee]);
1077 else
1078 $fdisplay(sdram_mem,"%0h",Bank3[ee]);
1079 end
1080 $fclose("sdram_mem.txt");
1081
1082 end
1083
1084
1085
1086 // // Timing Parameters for -75 (PC133) and CAS Latency = 2
1087 // specify
1088 // specparam
1089 tAH = 0.8, // Addr, Ba Hold Time
1090 tAS = 1.5, // Addr, Ba Setup Time
1091 tCH = 2.5, // Clock High-Level Width
1092 tCL = 2.5, // Clock Low-Level Width
1093 // tCK = 10.0, // Clock Cycle Time 100mhz
1094 // tCK = 7.5, // Clock Cycle Time 133mhz
1095 tCK = 7, // Clock Cycle Time 143mhz
1096 tDH = 0.8, // Data-in Hold Time
1097 tDS = 1.5, // Data-in Setup Time
1098 tCKH = 0.8, // CKE Hold Time
1099 tCKS = 1.5, // CKE Setup Time
1100 tCMH = 0.8, // CS#, RAS#, CAS#, WE#, DQM# Hold Time
1101 tCMS = 1.5; // CS#, RAS#, CAS#, WE#, DQM# Setup Time
1102 // tAH = 1, // Addr, Ba Hold Time
1103 // tAS = 1.5, // Addr, Ba Setup Time
1104 // tCH = 1, // Clock High-Level Width
1105 // tCL = 3, // Clock Low-Level Width
1106 tCK = 10.0, // Clock Cycle Time 100mhz
1107 tCK = 7.5, // Clock Cycle Time 133mhz
1108 // tCK = 7, // Clock Cycle Time 143mhz
1109 // tDH = 1, // Data-in Hold Time
1110 // tDS = 2, // Data-in Setup Time
1111 // tCKH = 1, // CKE Hold Time
1112 // tCKS = 2, // CKE Setup Time
1113 // tCMH = 0.8, // CS#, RAS#, CAS#, WE#, DQM# Hold Time
1114 // tCMS = 1.5; // CS#, RAS#, CAS#, WE#, DQM# Setup Time
1115 // $width (posedge Clk, tCH);
1116 // $width (negedge Clk, tCL);
1117 // $period (negedge Clk, tCK);
1118 // $period (posedge Clk, tCK);
1119 // $setuphold(posedge Clk, Cke, tCKS, tCKH);
1120 // $setuphold(posedge Clk, Cs_n, tCMS, tCMH);
1121 // $setuphold(posedge Clk, Cas_n, tCMS, tCMH);
1122 // $setuphold(posedge Clk, Ras_n, tCMS, tCMH);
1123 // $setuphold(posedge Clk, We_n, tCMS, tCMH);
1124 // $setuphold(posedge Clk, Addr, tAS, tAH);
1125 // $setuphold(posedge Clk, Ba, tAS, tAH);
1126 // $setuphold(posedge Clk, Dqm, tCMS, tCMH);
1127 // $setuphold(posedge Dq_chk, Dq, tDS, tDH);
1128 // endspecify
1129
1130 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.刷新就说完了,该附上源代码了
1 module sdram_aref(
2 //system signals
3 input sclk ,
4 input s_rst_n ,
5 //comunicat with ARBIT
6 input ref_en ,
7 output wire ref_req ,
8 output wire flag_ref_end ,
9 //others
10 output reg [3:0] aref_cmd ,
11 output wire [12:0] sdram_addr ,
12 input flag_init_end
13 );
14
15 //==============================================================================\
16 //*********************Define Parameter and Internal Signal ********************
17 //==============================================================================/
18 localparam DELAY_78us = 390 ;
19 localparam CMD_AREF = 4'b0001 ;
20 localparam CMD_NOP = 4'b0111 ;
21 localparam CMD_PRE = 4'b0010 ;
22 reg [3:0] cmd_cnt ;
23 reg [8:0] ref_cnt ;
24 reg flag_ref ;
25
26 //=============================================================================\
27 //********************** Main Code ***************************************
28 //=============================================================================/
29 always @(posedge sclk or negedge s_rst_n) begin
30 if(s_rst_n == 1'b0)
31 ref_cnt <= 9'd0;
32 else if(ref_cnt >= DELAY_78us)
33 ref_cnt <= 9'd0;
34 else if(flag_init_end == 1'b1)
35 ref_cnt <= ref_cnt +1'b1;
36 end
37
38 always @(posedge sclk or negedge s_rst_n) begin
39 if(s_rst_n == 1'b0)
40 flag_ref <= 1'b0;
41 else if(flag_ref_end == 1'b1)
42 flag_ref <= 1'b0;
43 else if(ref_en == 1'b1)
44 flag_ref <= 1'b1;
45 end
46
47 always @(posedge sclk or negedge s_rst_n ) begin
48 if(s_rst_n == 1'b0)
49 cmd_cnt <= 4'd0;
50 else if(flag_ref == 1'b1)
51 cmd_cnt <= cmd_cnt + 1'b1;
52 else
53 cmd_cnt <= 4'd0;
54 end
55
56
57 always @(posedge sclk or negedge s_rst_n) begin
58 if(s_rst_n == 1'b0)
59 aref_cmd <= CMD_NOP;
60 else case(cmd_cnt)
61 1: aref_cmd <= CMD_PRE;
62 2: aref_cmd <= CMD_AREF;
63 default:aref_cmd <= CMD_NOP;
64 endcase
65 end
66
67 assign flag_ref_end = (cmd_cnt >= 4'd3) ? 1'b1 : 1'b0;
68 assign sdram_addr = 13'd0_0100_0000_0000;
69 assign ref_req = (ref_cnt >= DELAY_78us) ? 1'b1 : 1'b0;
70
71
72
73 endmodule
sdram_aref
4.仲裁机制
为什么要这个仲裁机制,sdram工作是有刷新、写和读3个操作,我们需要这个仲裁机制来协调这三个操作,引用邓堪文老师一个图,大家一看就应该很明白了
5.具体的操作在sdram_top模块里,附上源码自己研究一下,这只写了三种状态,其他状态后面学习了在更新
1 module sdram_top(
2 //system signals
3 input sclk ,
4 input s_rst_n ,
5 //SDRAM Interfaces
6 output wire sdram_clk ,
7 output wire sdram_cke ,
8 output wire sdram_cs_n ,
9 output wire sdram_cas_n ,
10 output wire sdram_ras_n ,
11 output wire sdram_we_n ,
12 output wire [1:0] sdram_bank ,
13 output wire [12:0] sdram_addr ,
14 output wire [1:0] sdram_dqm ,
15 inout [15:0] sdram_dq
16 );
17
18 //==============================================================================\
19 //*********************Define Parameter and Internal Signal ********************
20 //==============================================================================/
21 localparam IDLE = 5'b0_0001 ;
22 localparam ARBIT = 5'b0_0010 ;
23 localparam AREF = 5'b0_0100 ;
24
25 //init module
26 wire flag_init_end ;
27 wire [3:0] init_cmd ;
28 wire [12:0] init_addr ;
29 //
30 reg [4:0] state ;
31 //refresh module
32 wire ref_req ;
33 wire flag_ref_end ;
34 reg ref_en ;
35 wire [3:0] ref_cmd ;
36 wire [12:0] ref_addr ;
37
38
39 //=============================================================================\
40 //********************** Main Code ***************************************
41 //=============================================================================/
42 always @(posedge sclk or negedge s_rst_n) begin
43 if(s_rst_n == 1'b0)
44 state <= IDLE;
45
46 else case(state)
47 IDLE:
48 if(flag_init_end == 1'b1)
49 state <= ARBIT;
50 else
51 state <= IDLE;
52 ARBIT:
53 if(ref_en == 1'b1)
54 state <= AREF;
55 else
56 state <= ARBIT;
57 AREF:
58 if(flag_ref_end == 1'b1)
59 state <= ARBIT;
60 else
61 state <=AREF;
62 default:
63 state <= IDLE;
64 endcase
65 end
66
67
68 //ref_en
69 always @(posedge sclk or negedge s_rst_n) begin
70 if(s_rst_n == 1'b0)
71 ref_en <= 1'b0;
72 else if(state == ARBIT && ref_req == 1'b1)
73 ref_en <= 1'b1;
74 else
75 ref_en <= 1'b0;
76 end
77
78 assign sdram_cke = 1'b1;
79 assign sdram_addr = (state == IDLE) ? init_addr : ref_addr;
80 assign {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = (state == IDLE) ? init_cmd : ref_cmd;
81 assign sdram_dqm = 2'd0;
82 assign sdram_clk = ~sclk;
83
84
85 sdram_ini sdram_ini_inst(
86 //systejm sign
87 .sclk (sclk ),
88 .s_rst_n (s_rst_n ),
89 //others
90 .cmd_reg (init_cmd ),
91 .sdram_addr (init_addr ),
92 .flag_init_end (flag_init_end )
93 );
94
95 sdram_aref sdram_aref_inst(
96 //system signals
97 .sclk (sclk ),
98 .s_rst_n (s_rst_n ),
99 //comunicat with ARBIT
100 .ref_en (ref_en ),
101 .ref_req (ref_req ),
102 .flag_ref_end (flag_ref_end ),
103 //others
104 .aref_cmd (ref_cmd ),
105 .sdram_addr (ref_addr ),
106 .flag_init_end (flag_init_end )
107 );
108
109
110 endmodule
sdram_top
6.最后老规矩放上仿真结果以及仿真波形图
初始化没有错,刷星也一直进行,没有错误
在看看波形图,没次看到这些信号就觉得自己就是个大牛,哈哈哈! 自恋了,但是还是个入了门的菜鸡。看图信号和数据都没问题,完美!
2018.9.14
由于学校突然断电,我写三个小时,马上写完的内容就没了,快被气死了。不想重写了,还有很多事情要做,顾不过来了。
先看一下现在做好的图片显示系统,用串口发送640*480的图片给FPGA,波特率是1562500,最快的了,VGA驱动显示屏。
说实话我不想再从写了,很烦,还有很多事要忙,真心要学的可以私聊我!
欢迎关注我的公众号:芯王国,有更多的FPGA&数字IC的技术分享,还可以获取开源FPGA项目!
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/129175.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...