| 1、设计目的:本项目展示如何用“至简设计法”设计SDARM,具体功能要求如下。  1)读写仲裁机制是:当如果同时出现读写请求时,如果上次执行了读操作,则此次执行写操作;如果上一次执行了写操作,则此次执行读操作。如果不是同时出现读写请求,则是什么请求就执行什么操作。  2)采用全页模式的读写操作,该模式在读、写完成时,需要给出预充电命令才能结束。  3)刷新请求始终优于读、写请求。  DDR的时序与SDRAM是相似的,学好SDRAM后,理解DDR2和DDR3就非常容易了。  2、至简设计代码实现(附录部分代码)  下面是使用至简设计法实现的SDRAM控制器,该控制器使用了四段式状态机,其他信号根据状态机对齐而设计,结构相当清晰,无论是设计还是调试,都非常容易,相信有一定基础的工程师,能感觉到这样设计的精简、奇妙之处,欢迎借鉴、学习。  网络上亦有相当多的SDRAM实现代码,欢迎您拿来与明德扬对比,我们对自身的代码设计就是有这样的自信。  1 //四段式状态机2
 3 //第一段:同步时序always模块,格式化描述次态寄存器迁移到现态寄存器
 4 always@(posedge clk or negedge rst_n)begin
 5 if(!rst_n)begin
 6 state_c <= IDL;
 7 end
 8 else begin
 9 state_c <= state_n;
 10 end
 11 end
 12
 13 //第二段:组合逻辑always模块,描述状态转移条件判断
 14 //只需要思考转移到哪里去
 15 always@(*)begin
 16 case(state_c)
 17 NOP:begin
 18 if(nop2pre_start)begin
 19 state_n = PRE;
 20 end
 21 else begin
 22 state_n = state_c;
 23 end
 24 end
 25 PRE:begin
 26 if(pre2aut_start)begin
 27 state_n = AUT;
 28 end
 29 else if(pre2idl_start)begin
 30 state_n = IDL;
 31 end
 32
 33 else begin
 34 state_n = state_c;
 35 end
 36 end
 37 AUT:begin
 38 if(aut2aut_start)begin
 39 state_n = AUT;
 40 end
 41 else if(aut2lmd_start)begin
 42 state_n = LMD;
 43 end
 44 else if(aut2idl_start)begin
 45 state_n = IDL;
 46 end
 47 end
 48 LMD:begin
 49 if(lmd2idl_start)begin
 50 state_n = IDL;
 51 end
 52 else begin
 53 state_n = state_c;
 54 end
 55 end
 56 IDL:begin
 57 if(idl2act_start)begin
 58 state_n = ACT;
 59 end
 60 else if(idl2aut_start)begin
 61 state_n = AUT;
 62 end
 63
 64 else begin
 65 state_n = state_c;
 66 end
 67 end
 68 ACT:begin
 69 if(act2red_start)begin
 70 state_n = RED;
 71 end
 72 else if(act2wrt_start)begin
 73 state_n = WRT;
 74 end
 75
 76 else begin
 77 state_n = state_c;
 78 end
 79 end
 80 RED:begin
 81 if(red2pre_start)begin
 82 state_n = PRE;
 83 end
 84 else begin
 85 state_n = state_c;
 86 end
 87 end
 88 WRT:begin
 89 if(wrt2pre_start)begin
 90 state_n = PRE;
 91 end
 92 else begin
 93 state_n = state_c;
 94 end
 95 end
 96 default:begin
 97 state_n = IDL;
 98 end
 99 endcase
 100 end
 101 //第三段:设计转移条件
 102 //相同现态的要放在一起,条件互斥,方便比较
 103 assign nop2pre_start = state_c==NOP && end_cnt;
 104
 105 assign pre2aut_start = state_c==PRE && init_flag==1 && end_cnt;
 106 assign pre2idl_start = state_c==PRE && init_flag==0 && end_cnt;
 107
 108 assign aut2aut_start = state_c==AUT && init_flag==1 && init_auto_flag==1 && end_cnt;
 109 assign aut2lmd_start = state_c==AUT && init_flag==1 && init_auto_flag==0 && end_cnt;
 110
 111 assign aut2idl_start = state_c==AUT && init_flag==0 && end_cnt;
 112
 113 assign lmd2idl_start = state_c==LMD && end_cnt;
 114
 115 assign idl2act_start = state_c==IDL && ref_req==0&& (wr_req||rd_req);
 116 assign idl2aut_start = state_c==IDL && ref_req ==1 ;
 117
 118 assign act2red_start = state_c==ACT && rd_flag==1 && end_cnt;
 119 assign act2wrt_start = state_c==ACT && rd_flag==0 && end_cnt;
 120
 121 assign red2pre_start = state_c==RED && end_cnt;
 122 assign wrt2pre_start = state_c==WRT && end_cnt;
 123
 124 always @(posedge clk or negedge rst_n)begin
 125 if(rst_n==1'b0)begin
 126 init_flag <= 1;
 127 end
 128 else if(lmd2idl_start)begin
 129 init_flag <= 0;
 130 end
 131 end
 132
 133 always @(posedge clk or negedge rst_n)begin
 134 if(rst_n==1'b0)begin
 135 init_auto_flag <= 1;
 136 end
 137 else if(aut2aut_start)begin
 138 init_auto_flag <= 0;
 139 end
 140 end
 141
 142 //刷新请求
 143 always @(posedge clk or negedge rst_n)begin
 144 if(rst_n==1'b0)begin
 145 ref_req <= 0;
 146 end
 147 else if(end_cnt_self)begin
 148 ref_req <= 1;
 149 end
 150 else if(idl2aut_start)begin
 151 ref_req <= 0;
 152 end
 153 end
 154
 155 //写响应
 156 assign wr_ack = idl2act_start==1&& (wr_req==1&&((rd_flag==1)||(rd_flag==0&&rd_req==0)));
 157 //读响应
 158 assign rd_ack = idl2act_start==1&& (rd_req==1&&((rd_flag==0)||(rd_flag==1&&wr_req==0)));
 159
 160 always @(posedge clk or negedge rst_n)begin
 161 if(rst_n==1'b0)begin
 162 rd_flag <= 0;
 163 end
 164 else if(rd_flag==0&&rd_ack==1)begin
 165 rd_flag <= 1;
 166 end
 167 else if(rd_flag==1&&wr_ack==1)begin
 168 rd_flag <= 0;
 169 end
 170 end
 171
 172
 173 //刷新时间计算
 174 always @(posedge clk or negedge rst_n)begin
 175 if(!rst_n)begin
 176 cnt_self <= 0;
 177 end
 178 else if(add_cnt_self)begin
 179 if(end_cnt_self)
 180 cnt_self <= 0;
 181 else
 182 cnt_self <= cnt_self + 1;
 183 end
 184 end
 185
 186 assign add_cnt_self = init_flag==0;
 187 assign end_cnt_self = add_cnt_self && cnt_self==1562-1 ;
 188
 189 //命令时间计数,此处使用了变量法,并且复用了一个计数器
 190 always @(posedge clk or negedge rst_n)begin
 191 if(!rst_n)begin
 192 cnt <= 0;
 193 end
 194 else if(add_cnt)begin
 195 if(end_cnt)
 196 cnt <= 0;
 197 else
 198 cnt <= cnt + 1;
 199 end
 200 end
 201
 202 assign add_cnt = state_c!=IDL;
 203 assign end_cnt = add_cnt && cnt==x-1 ;
 204
 205 //各个命令所需要的时间,在下面列出来就好了
 206 always @(*)begin
 207 if(state_c==NOP)begin
 208 x = INITIATE;
 209 end
 210 else if(state_c==PRE)begin
 211 x = TRP;
 212 end
 213 else if(state_c==AUT)begin
 214 x = TRC;
 215 end
 216 else if(state_c==LMD)begin
 217 x = TMRD;
 218 end
 219 else if(state_c==ACT)begin
 220 x = TRCD ;
 221 end
 222 else begin
 223 x = 256 ;
 224 end
 225 end
 226
 227 always @(posedge clk or negedge rst_n)begin
 228 if(rst_n==1'b0)begin
 229 cke <= 1;
 230 end
 231 else begin
 232 cke <= 1;
 233 end
 234 end
 235
 236 assign command = {cs,ras,cas,we};
 237
 238 //下面是产生命令的代码,由于状态机结构简单,要产生COMMAND是非常方便的
 239 //仅从名字下就可以看出代码是否正确
 240 always @(posedge clk or negedge rst_n)begin
 241 if(rst_n==1'b0)begin
 242 command <= 0;
 243 end
 244 else if(nop2pre_start||wrt2pre_start||red2pre_start)begin
 245 command <= precharge;
 246 end
 247 else if(pre2aut_start||aut2aut_start||idl2aut_start)begin
 248 command <= autorefresh;
 249 end
 250 else if(aut2lmd_start)begin
 251 command <= loadmode;
 252 end
 253 else if(idl2act_start)begin
 254 command <= active;
 255 end
 256 else if(act2red_start)begin
 257 command <= read;
 258 end
 259 else if(act2wrt_start)begin
 260 command <= write;
 261 end
 262 else begin
 263 command <= nop;
 264 end
 265
 266 end
 267
 268 always @(posedge clk or negedge rst_n)begin
 269 if(rst_n==1'b0)begin
 270 dqm <= 0;
 271 end
 272 else if(init_flag==1)begin
 273 dqm <= 2'b11;
 274 end
 275 else begin
 276 dqm <= 0;
 277 end
 278 end
 279
 280 always @(posedge clk or negedge rst_n)begin
 281 if(rst_n==1'b0)begin
 282 dq_out <= 0;
 283 end
 284 else begin
 285 dq_out <= wdata;
 286 end
 287 end
 288
 289 always @(posedge clk or negedge rst_n)begin
 290 if(rst_n==1'b0)begin
 291 dq_out_en <= 0;
 292 end
 293 else if(act2wrt_start)begin
 294 dq_out_en <= 1;
 295 end
 296 else if(wrt2pre_start)begin
 297 dq_out_en <= 0;
 298 end
 299 end
 300
 301
 302 always @(posedge clk or negedge rst_n)begin //256拍
 303 if(rst_n==1'b0)begin
 304 rdata_flag <= 0;
 305 end
 306 else if(act2red_start)begin
 307 rdata_flag <= 1;
 308 end
 309 else if(red2pre_start)begin
 310 rdata_flag <= 0;
 311 end
 312 end
 313
 314 always @(posedge clk or negedge rst_n)begin
 315 if(rst_n==1'b0)begin
 316 rdata_flag_ff0 <= 0;
 317 rdata_flag_ff1 <= 0;
 318 rdata_flag_ff2 <= 0;
 319 end
 320 else begin
 321 rdata_flag_ff0 <= rdata_flag;
 322 rdata_flag_ff1 <= rdata_flag_ff0;
 323 rdata_flag_ff2 <= rdata_flag_ff1;
 324
 325 end
 326 end
 327
 328
 329 always @(posedge clk or negedge rst_n)begin
 330 if(rst_n==1'b0)begin
 331 rdata <= 0;
 332 end
 333 else begin
 334 rdata <= dq_in;
 335 end
 336
 337 end
 338
 339 always @(posedge clk or negedge rst_n)begin
 340 if(rst_n==1'b0)begin
 341 rdata_vld <= 0;
 342 end
 343 else begin
 344 rdata_vld <= rd_flag_ff2;
 345 end
 346 end
 347
 348 always @(posedge clk or negedge rst_n)begin //锁存地址waddr;
 349 if(rst_n==1'b0)begin
 350 waddr_ff0 <= 0;
 351 end
 352 else if(idl2act_start)begin
 353 waddr_ff0 <= waddr;
 354 end
 355 end
 356
 357 always @(posedge clk or negedge rst_n)begin
 358 if(rst_n==1'b0)begin
 359 addr <= 0;
 360 end
 361 else if(nop2pre_start)begin
 362 addr <=12'b0100_0000_0000;
 363 end
 364 else if(aut2lmd_start)begin
 365 addr <= 12'b00_1_00_010_0_111;//latency Mode 为010 的情况
 366 end
 367 else if(idl2act_start)begin
 368 addr[7:0] <= waddr[19:8]; //行地址
 369 end
 370 else if(act2wrt_start||act2red_start)begin
 371 addr[7:0] <= waddr_ff0[7:0]; //列地址
 372 end
 373 end
 374
 375 always @(posedge clk or negedge rst_n)begin
 376 if(rst_n==1'b0)begin
 377 bank <=0;
 378 end
 379 else if(nop2pre_start)begin
 380 bank <= 2'b11;
 381 end
 382 else if(idl2act_start)begin
 383 bank <= waddr[21:20];
 384 end
 385 else if(act2red_start||act2wrt_start)begin
 386 bank < waddr_ff0[21:20];
 387 end
 388 else begin
 389 bank <= 0;
 390 end
 391 end
 392
 393
 394
 395
 
 QQ   1465617980 了解>>至简设计法  
 
 |