Hardware Design: SIE
Sign in or create your account | Project List | Help
Hardware Design: SIE Git Source Tree
Root/
| 1 | //---------------------------------------------------------------------------- |
| 2 | // Pipelined, asyncronous DDR Controller |
| 3 | // |
| 4 | // (c) Joerg Bornschein (<jb@capsec.org>) |
| 5 | //---------------------------------------------------------------------------- |
| 6 | module ddr_ctrl |
| 7 | #( |
| 8 | parameter phase_shift = 0, |
| 9 | parameter clk_freq = 100000000, |
| 10 | parameter clk_multiply = 12, |
| 11 | parameter clk_divide = 5, |
| 12 | parameter wait200_init = 26 |
| 13 | ) ( |
| 14 | input clk, |
| 15 | input reset, |
| 16 | // DDR ports |
| 17 | output [2:0] ddr_clk, |
| 18 | output [2:0] ddr_clk_n, |
| 19 | input ddr_clk_fb, |
| 20 | output ddr_ras_n, |
| 21 | output ddr_cas_n, |
| 22 | output ddr_we_n, |
| 23 | output [1:0] ddr_cke, |
| 24 | output [1:0] ddr_cs_n, |
| 25 | output [ `A_RNG] ddr_a, |
| 26 | output [ `BA_RNG] ddr_ba, |
| 27 | inout [ `DQ_RNG] ddr_dq, |
| 28 | inout [`DQS_RNG] ddr_dqs, |
| 29 | output [ `DM_RNG] ddr_dm, |
| 30 | // FML (FastMemoryLink) |
| 31 | output reg fml_done, |
| 32 | input [`FML_ADR_RNG] fml_adr, |
| 33 | input fml_rd, |
| 34 | input fml_wr, |
| 35 | input [`FML_DAT_RNG] fml_wdat, |
| 36 | input [`FML_BE_RNG] fml_wbe, |
| 37 | input fml_wnext, |
| 38 | output fml_rempty, |
| 39 | input fml_rnext, |
| 40 | output [`FML_DAT_RNG] fml_rdat, |
| 41 | // DCM phase shift control |
| 42 | output ps_ready, |
| 43 | input ps_up, |
| 44 | input ps_down, |
| 45 | // Logic Probe |
| 46 | output probe_clk, |
| 47 | input [7:0] probe_sel, |
| 48 | output reg [7:0] probe |
| 49 | ); |
| 50 | |
| 51 | wire [ `DQ_RNG] ddr_dq_i, ddr_dq_o; |
| 52 | wire [`DQS_RNG] ddr_dqs_i, ddr_dqs_o; |
| 53 | wire ddr_dqs_oe; |
| 54 | |
| 55 | //---------------------------------------------------------------------------- |
| 56 | // clock generator |
| 57 | //---------------------------------------------------------------------------- |
| 58 | wire clk_locked; |
| 59 | wire write_clk, write_clk90; |
| 60 | wire read_clk; |
| 61 | |
| 62 | wire reset_int = reset | ~clk_locked; |
| 63 | |
| 64 | ddr_clkgen #( |
| 65 | .phase_shift( phase_shift ), |
| 66 | .clk_multiply( clk_multiply ), |
| 67 | .clk_divide( clk_divide ) |
| 68 | ) clkgen ( |
| 69 | .clk( clk ), |
| 70 | .reset( reset ), |
| 71 | .locked( clk_locked ), |
| 72 | // ddr-clk |
| 73 | .read_clk( read_clk ), |
| 74 | .write_clk( write_clk ), |
| 75 | .write_clk90( write_clk90 ), |
| 76 | // phase shift control |
| 77 | .ps_ready( ps_ready ), |
| 78 | .ps_up( ps_up ), |
| 79 | .ps_down( ps_down ) |
| 80 | ); |
| 81 | |
| 82 | //---------------------------------------------------------------------------- |
| 83 | // async_fifos (cmd, wdata, rdata) |
| 84 | //---------------------------------------------------------------------------- |
| 85 | wire cba_fifo_full; |
| 86 | reg [`CBA_RNG] cba_fifo_din; |
| 87 | reg cba_fifo_we; |
| 88 | |
| 89 | wire wfifo_full; |
| 90 | wire [`WFIFO_RNG] wfifo_din; |
| 91 | wire wfifo_we; |
| 92 | |
| 93 | wire [`RFIFO_RNG] rfifo_dout; |
| 94 | wire rfifo_empty; |
| 95 | wire rfifo_next; |
| 96 | |
| 97 | assign wfifo_din = { ~fml_wbe, fml_wdat }; |
| 98 | assign wfifo_we = fml_wnext; |
| 99 | |
| 100 | assign fml_rdat = rfifo_dout; |
| 101 | assign fml_rempty = rfifo_empty; |
| 102 | assign rfifo_next = fml_rnext; |
| 103 | |
| 104 | //---------------------------------------------------------------------------- |
| 105 | // High-speed cmd, write and read datapath |
| 106 | //---------------------------------------------------------------------------- |
| 107 | ddr_wpath wpath0 ( |
| 108 | .clk( write_clk ), |
| 109 | .clk90( write_clk90 ), |
| 110 | .reset( reset_int ), |
| 111 | // CBA async fifo |
| 112 | .cba_clk( clk ), |
| 113 | .cba_din( cba_fifo_din ), |
| 114 | .cba_wr( cba_fifo_we ), |
| 115 | .cba_full( cba_fifo_full ), |
| 116 | // WDATA async fifo |
| 117 | .wdata_clk( clk ), |
| 118 | .wdata_din( wfifo_din ), |
| 119 | .wdata_wr( wfifo_we ), |
| 120 | .wdata_full( wfifo_full ), |
| 121 | // |
| 122 | .sample( sample ), |
| 123 | // DDR |
| 124 | .ddr_clk( ddr_clk ), |
| 125 | .ddr_clk_n( ddr_clk_n ), |
| 126 | .ddr_ras_n( ddr_ras_n ), |
| 127 | .ddr_cas_n( ddr_cas_n ), |
| 128 | .ddr_we_n( ddr_we_n ), |
| 129 | .ddr_a( ddr_a ), |
| 130 | .ddr_ba( ddr_ba ), |
| 131 | .ddr_dm( ddr_dm ), |
| 132 | .ddr_dq( ddr_dq_o ), |
| 133 | .ddr_dqs( ddr_dqs_o ), |
| 134 | .ddr_dqs_oe( ddr_dqs_oe ) |
| 135 | ); |
| 136 | |
| 137 | ddr_rpath rpath0 ( |
| 138 | .clk( read_clk ), |
| 139 | .reset( reset_int ), |
| 140 | // |
| 141 | .sample( sample ), |
| 142 | // |
| 143 | .rfifo_clk( clk ), |
| 144 | .rfifo_empty( rfifo_empty), |
| 145 | .rfifo_dout( rfifo_dout ), |
| 146 | .rfifo_next( rfifo_next ), |
| 147 | // DDR |
| 148 | .ddr_dq( ddr_dq_i ), |
| 149 | .ddr_dqs( ddr_dqs_i ) |
| 150 | ); |
| 151 | |
| 152 | //---------------------------------------------------------------------------- |
| 153 | // 7.8 us pulse generator |
| 154 | //---------------------------------------------------------------------------- |
| 155 | wire pulse78; |
| 156 | reg ar_req; |
| 157 | reg ar_done; |
| 158 | |
| 159 | ddr_pulse78 #( |
| 160 | .clk_freq( clk_freq ) |
| 161 | ) pulse78_gen ( |
| 162 | .clk( clk ), |
| 163 | .reset( reset_int ), |
| 164 | .pulse78( pulse78 ) |
| 165 | ); |
| 166 | |
| 167 | //---------------------------------------------------------------------------- |
| 168 | // Auto Refresh request generator |
| 169 | //---------------------------------------------------------------------------- |
| 170 | always @(posedge clk) |
| 171 | if (reset_int) |
| 172 | ar_req <= 0; |
| 173 | else |
| 174 | ar_req <= pulse78 | (ar_req & ~ar_done); |
| 175 | |
| 176 | // operations we might want to submit |
| 177 | wire [`CBA_RNG] ar_pre_cba; |
| 178 | wire [`CBA_RNG] ar_ar_cba; |
| 179 | |
| 180 | assign ar_pre_cba = { `DDR_CMD_PRE, 2'b00, 13'b1111111111111 }; |
| 181 | assign ar_ar_cba = { `DDR_CMD_AR, 2'b00, 13'b0000000000000 }; |
| 182 | |
| 183 | //---------------------------------------------------------------------------- |
| 184 | // Init & management |
| 185 | //---------------------------------------------------------------------------- |
| 186 | wire init_req; |
| 187 | reg init_ack; |
| 188 | wire [`CBA_RNG] init_cba; |
| 189 | wire init_done; |
| 190 | wire wait200; |
| 191 | |
| 192 | ddr_init #( |
| 193 | .wait200_init( wait200_init ) |
| 194 | ) init ( |
| 195 | .clk( clk ), |
| 196 | .reset( reset_int ), |
| 197 | .pulse78( pulse78 ), |
| 198 | .wait200( wait200 ), |
| 199 | .init_done( init_done ), |
| 200 | // |
| 201 | .mngt_req( init_req ), |
| 202 | .mngt_ack( init_ack ), |
| 203 | .mngt_cba( init_cba ) |
| 204 | ); |
| 205 | |
| 206 | //---------------------------------------------------------------------------- |
| 207 | // Active Bank Information |
| 208 | //---------------------------------------------------------------------------- |
| 209 | reg [`ROW_RNG] ba_row [3:0]; |
| 210 | reg [3:0] ba_active; |
| 211 | |
| 212 | //---------------------------------------------------------------------------- |
| 213 | // FML decoding |
| 214 | //---------------------------------------------------------------------------- |
| 215 | wire [`FML_ADR_BA_RNG] fml_ba = fml_adr[`FML_ADR_BA_RNG]; |
| 216 | wire [`FML_ADR_ROW_RNG] fml_row = fml_adr[`FML_ADR_ROW_RNG]; |
| 217 | wire [`FML_ADR_COL_RNG] fml_col = fml_adr[`FML_ADR_COL_RNG]; |
| 218 | |
| 219 | wire [`FML_ADR_ROW_RNG] fml_cur_row; // current active row in sel. bank |
| 220 | assign fml_cur_row = ba_row[fml_ba]; |
| 221 | |
| 222 | wire fml_row_active; // is row in selected ba really active? |
| 223 | assign fml_row_active = ba_active[fml_ba]; |
| 224 | |
| 225 | |
| 226 | /* |
| 227 | wire fml_row_active = (fml_ba == 0) ? ba0_active : // is row in selected |
| 228 | (fml_ba == 1) ? ba1_active : // bank really active? |
| 229 | (fml_ba == 2) ? ba2_active : |
| 230 | ba3_active ; |
| 231 | */ |
| 232 | |
| 233 | // request operation iff correct bank is active |
| 234 | wire fml_req = fml_rd | fml_wr; |
| 235 | wire fml_row_match = (fml_row == fml_cur_row) & fml_row_active; |
| 236 | wire fml_pre_req = fml_req & ~fml_row_match & fml_row_active; |
| 237 | wire fml_act_req = fml_req & ~fml_row_active; |
| 238 | wire fml_read_req = fml_rd & fml_row_match & ~fml_done; |
| 239 | wire fml_write_req = fml_wr & fml_row_match & ~fml_done; |
| 240 | |
| 241 | // actual operations we might want to submit |
| 242 | wire [`CBA_RNG] fml_pre_cba; |
| 243 | wire [`CBA_RNG] fml_act_cba; |
| 244 | wire [`CBA_RNG] fml_read_cba; |
| 245 | wire [`CBA_RNG] fml_write_cba; |
| 246 | |
| 247 | assign fml_pre_cba = { `DDR_CMD_PRE, fml_ba, 13'b0 }; |
| 248 | assign fml_act_cba = { `DDR_CMD_ACT, fml_ba, fml_row }; |
| 249 | assign fml_read_cba = { `DDR_CMD_READ, fml_ba, {3'b000}, fml_col, {3'b000} }; |
| 250 | assign fml_write_cba = { `DDR_CMD_WRITE, fml_ba, {3'b000}, fml_col, {3'b000} }; |
| 251 | |
| 252 | //---------------------------------------------------------------------------- |
| 253 | // Schedule and issue commands |
| 254 | //---------------------------------------------------------------------------- |
| 255 | |
| 256 | parameter s_init = 0; |
| 257 | parameter s_idle = 1; |
| 258 | parameter s_ar = 2; |
| 259 | parameter s_reading = 3; |
| 260 | |
| 261 | reg [1:0] state; |
| 262 | |
| 263 | always @(posedge clk) |
| 264 | begin |
| 265 | if (reset_int) begin |
| 266 | state <= s_init; |
| 267 | ba_active <= 0; |
| 268 | ba_row[0] <= 0; |
| 269 | ba_row[1] <= 0; |
| 270 | ba_row[2] <= 0; |
| 271 | ba_row[3] <= 0; |
| 272 | |
| 273 | fml_done <= 0; |
| 274 | init_ack <= 0; |
| 275 | cba_fifo_we <= 0; |
| 276 | ar_done <= 0; |
| 277 | end else begin |
| 278 | fml_done <= 0; |
| 279 | init_ack <= 0; |
| 280 | cba_fifo_we <= 0; |
| 281 | ar_done <= 0; |
| 282 | |
| 283 | case (state) |
| 284 | s_init: begin |
| 285 | if (init_done) |
| 286 | state <= s_idle; |
| 287 | |
| 288 | if (init_req & ~cba_fifo_full) begin |
| 289 | cba_fifo_we <= 1; |
| 290 | cba_fifo_din <= init_cba; |
| 291 | init_ack <= 1; |
| 292 | end |
| 293 | end |
| 294 | s_idle: begin |
| 295 | if (fml_read_req & ~cba_fifo_full) begin |
| 296 | cba_fifo_we <= 1; |
| 297 | cba_fifo_din <= fml_read_cba; |
| 298 | fml_done <= 1; |
| 299 | end else if (fml_write_req & ~cba_fifo_full) begin |
| 300 | cba_fifo_we <= 1; |
| 301 | cba_fifo_din <= fml_write_cba; |
| 302 | fml_done <= 1; |
| 303 | end else if (ar_req & ~cba_fifo_full) begin |
| 304 | cba_fifo_we <= 1; |
| 305 | cba_fifo_din <= ar_pre_cba; |
| 306 | ar_done <= 1; |
| 307 | ba_active <= 'b0; |
| 308 | state <= s_ar; |
| 309 | end else if (fml_pre_req & ~cba_fifo_full) begin |
| 310 | cba_fifo_we <= 1; |
| 311 | cba_fifo_din <= fml_pre_cba; |
| 312 | ba_active[fml_ba] <= 0; |
| 313 | end else if (fml_act_req & ~cba_fifo_full) begin |
| 314 | cba_fifo_we <= 1; |
| 315 | cba_fifo_din <= fml_act_cba; |
| 316 | ba_active[fml_ba] <= 1; |
| 317 | ba_row[fml_ba] <= fml_row; |
| 318 | end |
| 319 | end |
| 320 | s_ar: begin |
| 321 | if (~cba_fifo_full) begin |
| 322 | cba_fifo_we <= 1; |
| 323 | cba_fifo_din <= ar_ar_cba; |
| 324 | state <= s_idle; |
| 325 | end |
| 326 | end |
| 327 | endcase |
| 328 | end |
| 329 | end |
| 330 | |
| 331 | //---------------------------------------------------------------------------- |
| 332 | // Demux dqs and dq |
| 333 | //---------------------------------------------------------------------------- |
| 334 | assign ddr_cke = {~wait200, ~wait200}; // bring up CKE as soon 200us wait is finished |
| 335 | |
| 336 | assign ddr_dqs = ddr_dqs_oe!=1'b0 ? ddr_dqs_o : 'bz; |
| 337 | assign ddr_dq = ddr_dqs_oe!=1'b0 ? ddr_dq_o : 'bz; |
| 338 | |
| 339 | assign ddr_dqs_i = ddr_dqs; |
| 340 | assign ddr_dq_i = ddr_dq; |
| 341 | |
| 342 | assign ddr_cs_n = 2'b00; |
| 343 | |
| 344 | //---------------------------------------------------------------------------- |
| 345 | // Probes |
| 346 | //---------------------------------------------------------------------------- |
| 347 | assign probe_clk = clk; |
| 348 | |
| 349 | always @(*) |
| 350 | begin |
| 351 | case (probe_sel) |
| 352 | 8'h00: probe <= { cba_fifo_we, wfifo_we, rfifo_next, 1'b0, cba_fifo_full, wfifo_full, rfifo_empty, 1'b0 }; |
| 353 | 8'h01: probe <= { write_clk, write_clk90, read_clk, 5'b00000 }; |
| 354 | 8'h10: probe <= { rfifo_empty, rfifo_next, rfifo_dout[ 5: 0] }; |
| 355 | 8'h11: probe <= { rfifo_empty, rfifo_next, rfifo_dout[13: 8] }; |
| 356 | 8'h12: probe <= { rfifo_empty, rfifo_next, rfifo_dout[21:16] }; |
| 357 | 8'h13: probe <= { rfifo_empty, rfifo_next, rfifo_dout[29:24] }; |
| 358 | 8'h20: probe <= wfifo_din[ 7:0]; |
| 359 | 8'h21: probe <= wfifo_din[15:8]; |
| 360 | 8'h20: probe <= wfifo_din[23:16]; |
| 361 | 8'h21: probe <= wfifo_din[31:24]; |
| 362 | 8'h30: probe <= cba_fifo_din[17:10]; |
| 363 | 8'h31: probe <= cba_fifo_din[ 9:2]; |
| 364 | default: probe <= 0'b0; |
| 365 | endcase |
| 366 | end |
| 367 | |
| 368 | |
| 369 | endmodule |
| 370 | |
| 371 |
Branches:
master
