| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 | // -----------------------------------------------------------------------////   Copyright 2010-2021 H. Peter Anvin - All Rights Reserved////   This program is free software; you can redistribute it and/or modify//   it under the terms of the GNU General Public License as published by//   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,//   Boston MA 02110-1301, USA; either version 2 of the License, or//   (at your option) any later version; incorporated herein by reference.//// -----------------------------------------------------------------------//// Simple SDRAM controller////  Very simple non-parallelizing SDRAM controller.//////  Two ports are provided: port 0 is single byte per transaction,//  and has highest priority; it is intended for transactions from the//  ABC-bus. Port 1 does aligned 4-byte accesses with byte enables.//  Port 2 does aligned 8-byte accesses, write only, with no byte//  enables; it supports streaming from a FIFO.////  All signals are in the sdram clock domain.////  [rw]ack is asserted at the beginning of a read- or write cycle and//  deasserted afterwards; rready is asserted once all data is read and//  the read data (rdX port) is valid; it remains asserted after the//  transaction is complete and rack is deasserted.//module sdram#( parameter   //  Timing parameters   //  The parameters are hardcoded for Micron MT48LC16M16A2-6A,   //  per datasheet:   //			  100 MHz  167 MHz   //    ----------------------------------------------------------   //    CL                     2        3    READ to data out   //    tRCD	    18 ns       2        3    ACTIVE to READ/WRITE   //    tRFC	    60 ns       6       10    REFRESH to ACTIVE   //    tRP        18 ns       2        3    PRECHARGE to ACTIVE/REFRESH   //    tRAS	    42 ns       5        7    ACTIVE to PRECHARGE   //    tRC        60 ns       6       10    ACTIVE to ACTIVE (same bank)   //    tRRD       12 ns       2        2    ACTICE to ACTIVE (different bank)   //    tWR        12 ns       2        2    Last write data to PRECHARGE   //    tMRD                   2	 2    MODE REGISTER to ACTIVE/REFRESH   //   //    These parameters are set by power of 2:   //    tREFi 64/8192 ms     781     1302    Refresh time per row (max)   //    tP        100 us   10000    16667    Time until first command (min)   t_cl		=  3,   t_rcd	=  3,   t_rfc	= 10,   t_rp		=  3,   t_ras	=  7,   t_rc		= 10,   t_rrd        =  2,   t_wr		=  2,   t_mrd	=  2,   t_refi_lg2	= 10,	// 1024 cycles   t_p_lg2	= 15,	// 32768 cycles   burst_lg2	=  1	// log2(burst length))(	      // Reset and clock	      input		rst_n,	      input		clk,	      input		out_clk, // Phase shifted external clock	      // SDRAM hardware interface	      output		sr_clk, // SDRAM clock output buffer	      output		sr_cke, // SDRAM clock enable	      output		sr_cs_n, // SDRAM CS#	      output		sr_ras_n, // SDRAM RAS#	      output		sr_cas_n, // SDRAM CAS#	      output		sr_we_n, // SDRAM WE#	      output [1:0]	sr_dqm, // SDRAM DQM (per byte)	      output [1:0]	sr_ba, // SDRAM bank selects	      output [12:0]	sr_a, // SDRAM address bus	      inout [15:0]	sr_dq, // SDRAM data bus	      // Port 0: single byte, high priority	      input [24:0]	a0, // Address, must be stable until ack	      output reg [7:0]	rd0, // Data from SDRAM	      input		rrq0, // Read request	      output reg	rack0, // Read ack (transaction started)	      output reg	rready0, // Read data valid	      input [7:0]	wd0, // Data to SDRAM	      input		wrq0, // Write request	      output reg	wack0, // Write ack (data latched)	      // Port 1	      input [24:2]	a1,	      output reg [31:0] rd1,	      input		rrq1,	      output reg	rack1,	      output reg	rready1,	      input [31:0]	wd1,	      input [3:0]	wstrb1,	      output reg	wack1,	      // Port 2	      input [24:1]	a2,	      input [15:0]	wd2,	      input [1:0]	wrq2,	      output reg	wacc2 // Data accepted, advance data & addr	      );`include "functions.sv"		// For modelsim   wire				wrq1 = |wstrb1;   // Mode register data   wire			    mrd_wburst = 1'b1;     // Write bursts enabled   wire [2:0]		    mrd_cl     = t_cl;   wire [2:0]		    mrd_burst  = burst_lg2;   wire			    mrd_interleave = 1'b0; // Interleaved bursts   wire [12:0] mrd_val  = { 3'b000,		// Reserved			    ~mrd_wburst,	// Write burst disable			    2'b00,		// Normal operation			    mrd_cl,		// CAS latency			    mrd_interleave,	// Interleaved bursts			    mrd_burst };	// Burst length   // Where to issue a PRECHARGE when we only want to read one word   // (terminate the burst as soon as possible, but no sooner...)   localparam t_pre_rd_when = max(t_ras, t_rcd + 1);   // Where to issue a PRECHARGE when we only want to write one word   // (terminate the burst as soon as possible, but no sooner...)   localparam t_pre_wr_when = max(t_ras, t_rcd + t_wr);   // Actual burst length (2^burst_lg2)   localparam burst_n = 1 << burst_lg2;   // Command opcodes and attributes (is_rfsh, CS#, RAS#, CAS#, WE#)   localparam	cmd_desl = 5'b0_1111; // Deselect (= NOP)   localparam	cmd_nop  = 5'b0_0111;  // NO OPERATION   localparam	cmd_bst  = 5'b0_0110;  // BURST TERMINATE   localparam	cmd_rd   = 5'b0_0101;  // READ   localparam	cmd_wr   = 5'b0_0100;  // WRITE   localparam	cmd_act  = 5'b0_0011;  // ACTIVE   localparam	cmd_pre  = 5'b0_0010;  // PRECHARGE   localparam	cmd_ref  = 5'b1_0001;  // AUTO REFRESH   localparam	cmd_mrd  = 5'b0_0000;  // LOAD MODE REGISTER   reg [4:0]	dram_cmd;   wire		is_rfsh  = dram_cmd[4];   assign	sr_cs_n  = dram_cmd[3];   assign	sr_ras_n = dram_cmd[2];   assign	sr_cas_n = dram_cmd[1];   assign	sr_we_n  = dram_cmd[0];   assign       sr_cke   = 1'b1;`ifdef SD_CLK_USE_DDIO   // SDRAM output clock buffer. The SDRAM output clock is   // inverted with respect to our internal clock, so that   // the SDRAM sees the positive clock edge in the middle of   // our clocks.   //   // Use a DDIO buffer for best performance   // For EP4CE15 only could use a secondary PLL here, but it   // isn't clear it buys us a whole lot.   //   // This buffer is driven by a separate PLL output, so that   // the phase shift between the clock and the outputs/inputs   // can be tuned.   ddio_out sr_clk_out (			.aclr ( 1'b0 ),			.datain_h ( 1'b1 ),			.datain_l ( 1'b0 ),			.outclock ( out_clk ),			.dataout ( sr_clk )			);`else // !`ifdef SD_CLK_USE_DDIO   // Dedicated clock pin   assign sr_clk = out_clk;`endif   // SDRAM output signal registers   reg [12:0]		    dram_a;   assign		    sr_a = dram_a;   reg [1:0]		    dram_ba;   assign		    sr_ba = dram_ba;   reg [1:0]		    dram_dqm;   assign		    sr_dqm = dram_dqm;   reg [15:0]		    dram_d; // Data to DRAM   reg			    dram_d_en; // Drive data out   assign		    sr_dq = dram_d_en ? dram_d : 16'hzzzz;   // State machine and counters   reg [t_refi_lg2-2:0]	      rfsh_ctr;  // Refresh timer   wire			      rfsh_ctr_msb = rfsh_ctr[t_refi_lg2-2];   reg			      rfsh_ctr_last_msb;   wire			      rfsh_tick = rfsh_ctr_last_msb & ~rfsh_ctr_msb;   reg [t_p_lg2:t_refi_lg2-1] init_ctr;  // Reset to init counter   reg [1:0]		      rfsh_prio; // Refresh priority					 // Bit 0 - refresh if opportune					 // Bit 1 - refresh urgent   // The actual values are unimportant; the compiler will optimize   // the state machine implementation.   typedef enum logic [2:0] {	 st_reset,		// Reset until init timer expires	 st_init_rfsh,		// Refresh cycles during initialization	 st_init_mrd,		// MRD register write during initialization	 st_idle,		// Idle state: all banks precharged	 st_rfsh,	 st_rd_wr,		// Port 0/1 transaction	 st_pre_idle,	 st_wr2			// Port 2 write (burstable)   } state_t;   state_t state = st_reset;   reg		is_write;   always @(posedge clk or negedge rst_n)     if (~rst_n)       begin	  rfsh_ctr  <= 1'b0;	  rfsh_prio <= 2'b00;	  init_ctr  <= 1'b0;       end     else       begin	  rfsh_ctr           <= rfsh_ctr + 1'b1;	  rfsh_ctr_last_msb  <= rfsh_ctr_msb;	  // Refresh priority management	  if (is_rfsh)	    rfsh_prio <= 2'b00; // This is a refresh cycle	  else if (rfsh_tick)	    rfsh_prio <= { rfsh_prio[0], 1'b1 };	  // The refresh counter is also used as a prescaler	  // for the initialization counter.	  // Note that means init_ctr is two cycles "behind"	  // rfsh_ctr; this is totally fine.	  init_ctr <= init_ctr + rfsh_tick;       end // else: !if(~rst_n)   reg [5:0] op_ctr;		// Cycle into the current state   wire [3:0] op_cycle    = op_ctr[3:0]; // Cycle into the current command   wire [1:0] init_op_ctr = op_ctr[5:4]; // Init operation counter   reg	      op_zero;		// op_cycle wrap around (init_op_ctr changed)   reg [31:0] wdata_q;   reg [ 3:0] be_q;   reg [ 9:0] col_addr;   reg	      wrq2_more;   //   // Careful with the timing here... there is one cycle between   // registers and wires, and the DRAM observes the clock 1/2   // cycle from the internal logic. This affects read timing.   //   // Note that rready starts out as 1. This allows a 0->1 detection   // on the rready line to be used as cycle termination signal.   //   always @(posedge clk or negedge rst_n)     if (~rst_n)       begin	  dram_cmd      <= cmd_desl;	  dram_a        <= 13'hxxxx;	  dram_ba       <= 2'bxx;	  dram_dqm      <= 2'b00;	  dram_d        <= 16'hxxxx;	  dram_d_en     <= 1'b1; // Don't float except during read	  op_ctr        <= 6'h0;	  op_zero       <= 1'b0;	  state         <= st_reset;	  is_write      <= 1'bx;	  rack0         <= 1'b0;	  rready0       <= 1'b1;	  wack0         <= 1'b0;	  rack1         <= 1'b0;	  rready1       <= 1'b1;	  wack1         <= 1'b0;	  wacc2         <= 1'b0;	  wrq2_more     <= 1'bx;	  wdata_q       <= 32'hxxxx_xxxx;	  be_q          <= 4'bxxxx;	  col_addr      <= 10'hxxx;       end     else       begin	  // Default values	  // Note: dram_ba are preserved	  dram_a        <= 13'hxxxx;	  dram_dqm      <= 2'b00;	  dram_d        <= 16'haaaa;	  dram_cmd      <= cmd_nop;	  dram_d_en     <= 1'b1; // Don't float except during read	  if (state != st_rd_wr)	    begin	       rack0 <= 1'b0;	       wack0 <= 1'b0;	       rack1 <= 1'b0;	       wack1 <= 1'b0;	    end	  wacc2 <= 1'b0;	  if (state == st_reset || state == st_idle)	    begin	       op_ctr    <= 6'b0;	       op_zero   <= 1'b0;	    end	  else	    begin	       op_ctr <= op_ctr + 1'b1;	       op_zero <= &op_cycle; // About to wrap around	    end // else: !if(state == st_reset || state == st_idle)	  case (state)	    st_reset:	      begin		 dram_a[10] <= 1'b1; // Precharge all banks		 dram_cmd  <= cmd_nop;		 if (init_ctr[t_p_lg2])		   begin		      dram_cmd <= cmd_pre;		      state    <= st_init_rfsh;		   end	      end	    st_init_rfsh:	      begin		 if (op_zero)		   begin		      dram_cmd <= cmd_ref;		      if (init_op_ctr == 2'b11)			state <= st_init_mrd;		   end	      end	    st_init_mrd:	      begin		 dram_a <= mrd_val;		 dram_ba <= 2'b00;		 if (op_zero)		   if (init_op_ctr[0])		     state <= st_idle;		   else		     dram_cmd <= cmd_mrd;	      end	    st_idle:	      begin		 is_write <= 1'bx;		 be_q     <= 4'bxxxx;		 wdata_q  <= 32'hxxxx_xxxx;		 // A data transaction starts with ACTIVE command;		 // a refresh transaction starts with REFRESH.		 // Port 0 has the highest priority, then		 // refresh, then port 1; a refresh transaction		 // is started opportunistically if nothing is		 // pending and the refresh counter is no less than		 // half expired.		 dram_a  <= 13'h1bb;		 dram_ba <= 2'bxx;		 dram_d  <= 16'hbbbb;		 casez ( {rrq0|wrq0, rrq1|wrq1, wrq2[0], rfsh_prio} )		   5'b1????:		     begin			// Begin port 0 transaction			dram_cmd     <= cmd_act;			dram_a       <= a0[24:12];			dram_ba      <= a0[11:10];			col_addr     <= a0[9:0];			if ( wrq0 )			  begin			     state    <= st_rd_wr;			     wack0    <= 1'b1;			     wdata_q  <= {16'hxxxx, wd0, wd0};			     be_q     <= {2'b00, a0[0], ~a0[0]};			     is_write <= 1'b1;			  end			else			  begin			     state    <= st_rd_wr;			     rack0    <= 1'b1;			     rready0  <= 1'b0;			     is_write <= 1'b0;			  end		     end		   5'b01?0?:		     begin			// Begin port 1 transaction			dram_cmd     <= cmd_act;			dram_a       <= a1[24:12];			dram_ba      <= a1[11:10];			col_addr     <= { a1[9:2], 2'b00 };			if ( wrq1 )			  begin			     state    <= st_rd_wr;			     wack1    <= 1'b1;			     wdata_q  <= wd1;			     be_q     <= wstrb1;			     is_write <= 1'b1;			  end			else			  begin			     state    <= st_rd_wr;			     rack1    <= 1'b1;			     rready1  <= 1'b0;			     is_write <= 1'b0;			  end		     end		   5'b0??1?, 5'b00?01:		     begin			// Begin refresh transaction			dram_cmd    <= cmd_ref;			state       <= st_rfsh;		     end		   5'b00100:		     begin			// Begin port 2 write			dram_cmd    <= cmd_act;			dram_a      <= a2[24:12];			dram_ba     <= a2[11:10];			state       <= st_wr2;		     end		   default:		     begin			dram_cmd    <= cmd_desl;			state       <= st_idle;		     end		 endcase // casez ( {rrq0|wrq0, rrq1|wrq1, rfsh_prio} )	      end // case: st_idle	    st_rfsh:	      begin		 if (op_cycle == t_rfc-2)		   state <= st_idle;	      end	    st_rd_wr:	      begin		 dram_d_en <= is_write;		 dram_dqm  <= {2{is_write}};		 dram_d <= 16'hcccc;		 // Commands		 //		 // This assumes:		 // tRCD =  3		 // rRRD =  2		 // CL   =  3		 // tRC  = 10		 // tRAS =  7		 // tWR  =  2		 // tRP  =  3		 //		 case (op_cycle)		   2: begin		      dram_a[10]   <= 1'b0; // No auto precharge		      dram_a[8:0]  <= col_addr[9:1];		      dram_cmd     <= is_write ? cmd_wr : cmd_rd;		      dram_d       <= wdata_q[15:0];		      dram_dqm     <= {2{is_write}} & ~be_q[1:0];		      wdata_q      <= { 16'hdddd, wdata_q[31:16] };		      be_q         <= { 2'hxx, be_q[3:2] };		   end		   3: begin		      dram_d       <= wdata_q[15:0];		      dram_dqm     <= {2{is_write}} & ~be_q[1:0];		      wdata_q      <= { 16'heeee, wdata_q[31:16] };		      be_q         <= 4'bxxxx;		   end		   6: begin		      // Earliest legal cycle to precharge		      // It seems auto precharge violates tRAS(?)		      // so do it explicitly.		      dram_a[10]   <= 1'b1; // One bank		      dram_cmd     <= cmd_pre;		   end		   // CL+2 cycles after the read command		   // The +2 accounts for internal and I/O delays		   7: begin		      if (rack0)			rd0 <= col_addr[0] ? sr_dq[15:8] : sr_dq[7:0];		      rready0 <= rready0 | rack0;		      if (rack1)			rd1[15:0] <= sr_dq;		   end		   8: begin		      if (rack1)			rd1[31:16] <= sr_dq;		      rready1 <= rready1 | rack1;		      state <= st_pre_idle;		   end		 endcase // case (op_cycle)	      end // case: st_rd_wr	    st_pre_idle:	      begin		 // Last cycle before tRC is a separate state		 // so that rack/wack will be cleared		 dram_d_en <= is_write;		 dram_dqm  <= {2{is_write}};		 state <= st_idle;	      end	    st_wr2:	      begin		 // Streamable write from flash ROM		 dram_d      <= wd2;		 dram_a[10]  <= 1'b0;  // No auto precharge/precharge one bank		 dram_a[8:0] <= a2[9:1];		 case (op_cycle)		   0: begin		      wacc2 <= 1'b1;		   end		   1: begin		      wacc2 <= 1'b1;		   end		   2: begin		      dram_cmd  <= cmd_wr;		      wacc2     <= 1'b1;		      wrq2_more <= wrq2[1];		   end		   3: begin		      wacc2    <= 1'b1;		   end		   4: begin		      dram_cmd  <= cmd_wr;		      if (wrq2_more &			  ~(rrq0|wrq0|rrq1|wrq1|(|rfsh_prio)|(&dram_a[8:2])))			begin			   // Burst can continue			   wacc2       <= 1'b1;			   op_ctr[3:0] <= 4'd1;			end		   end // case: 4		   6: begin		      dram_dqm    <= 2'b11; // This shouldn't be necessary?!		   end		   7: begin		      // tWR completed		      dram_cmd    <= cmd_pre;		      dram_dqm    <= 2'b11;		   end		   8: begin		      dram_dqm    <= 2'b11;		   end		   9: begin		      // tRP will be complete in the next cycle		      dram_dqm    <= 2'b11;		      state <= st_idle;		   end		 endcase // case (op_cycle)	      end // case: st_wr2	  endcase // case(state)       end // else: !if(~rst_n)endmodule // dram
 |