Quellcode durchsuchen

sdram: make the bus protocol actually work sanely

H. Peter Anvin vor 3 Jahren
Ursprung
Commit
2517eac8ba
1 geänderte Dateien mit 112 neuen und 84 gelöschten Zeilen
  1. 112 84
      sdram.sv

+ 112 - 84
sdram.sv

@@ -18,19 +18,15 @@
 //
 //  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 8-strobe burst transactions. If additional ports
-//  are needed, the intent is to add an arbiter to port 1.
+//  ABC-bus. Port 1 does 4-byte accesses with arbitrary alignment and
+//  byte enables.
 //
 //  All signals are in the sdram clock domain.
 //
-//  The ack signals are arrays that give (some) advance notification:
-//  e.g. rack0[1] is asserted exactly one cycle before rack0[0].
-//
-//  rack*[0] is asserted during the first cycle rd* is valid.
-//  wack*[0] is asserted during the cycle after wd* was sampled.
-//
-//  Thus, especially for bursts on port 1, generally rack1[0] and
-//  wack1[1] are the relevant signals.
+//  [rw]ack is asserted at the beginning of a read- or write cycle and
+//  deasserted afterwards; rvalid 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
@@ -71,43 +67,45 @@ module sdram
 )
 (
 	      // Reset and clock
-	      input			  rst_n,
-	      input			  clk,
+	      input		rst_n,
+	      input		clk,
 
 	      // 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
+	      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
+	      input [24:0]	a0, // Address, must be stable until ack
 
-	      output reg [7:0]		  rd0, // Data from SDRAM
-	      input			  rrq0, // Read request
-	      output reg [t_rcd+t_cl+3:0] rack0, // Read ack
+	      output reg [7:0]	rd0, // Data from SDRAM
+	      input		rrq0, // Read request
+	      output reg	rack0, // Read ack (transaction started)
+	      output reg	rvalid0, // Read data valid
 
-	      input [7:0]		  wd0, // Data to SDRAM
-	      input			  wrq0, // Write request
-	      output reg		  wack0, // Write ack (data latched)
+	      input [7:0]	wd0, // Data to SDRAM
+	      input		wrq0, // Write request
+	      output reg	wack0, // Write ack (data latched)
 
 	      // Port 1
-	      input [24:2]		  a1,
-	      input [7:0]		  be1, // Write byte enable
+	      input [24:2]	a1,
+	      input [7:0]	be1, // Write byte enable
 
-	      output reg [31:0]		  rd1,
-	      input			  rrq1,
-	      output reg [t_rcd+t_cl+3:0] rack1,
+	      output reg [31:0] rd1,
+	      input		rrq1,
+	      output reg	rack1,
+	      output reg	rvalid1,
 
-	      input [31:0]		  wd1,
-	      input			  wrq1,
-	      output reg		  wack1
+	      input [31:0]	wd1,
+	      input		wrq1,
+	      output reg	wack1
 	      );
 
    // Mode register data
@@ -179,8 +177,10 @@ module sdram
    reg			    dram_d_en; // Drive data out
    assign		    sr_dq = dram_d_en ? dram_d : 16'hzzzz;
 
-   // Input register for SDRAM data
+   // I/O cell input register for SDRAM data
    reg [15:0]		    dram_q;
+   always @(posedge clk)
+     dram_q <= sr_dq;
 
    // State machine and counters
    reg [t_refi_lg2-2:0]	      rfsh_ctr;  // Refresh timer
@@ -191,7 +191,6 @@ module sdram
    reg [1:0]		      rfsh_prio; // Refresh priority
 					 // Bit 0 - refresh if opportune
 					 // Bit 1 - refresh urgent
-   reg			      port;	 // Port being serviced
 
    reg [3:0]		      op_cycle;	// Cycles into the current operation
 
@@ -254,7 +253,7 @@ module sdram
        end // else: !if(~rst_n)
 
    reg [31:0] wdata_q;
-   reg [ 6:0] be_q;
+   reg [ 7:0] be_q;
 
    //
    // Careful with the timing here... there is one cycle between
@@ -271,13 +270,20 @@ module sdram
 	  dram_dqm      <= 2'b00;
 	  dram_d        <= 16'hxxxx;
 	  dram_d_en     <= 1'b1; // Don't float except during read
+
 	  op_cycle      <= 1'b0;
 	  state         <= st_reset;
 
-	  rack0       <= 1'b0;
-	  wack0       <= 1'b0;
-	  rack1       <= 1'b0;
-	  wack1       <= 1'b0;
+	  rack0         <= 1'b0;
+	  rvalid0       <= 1'b0;
+	  wack0         <= 1'b0;
+
+	  rack1         <= 1'b0;
+	  rvalid1       <= 1'b0;
+	  wack1         <= 1'b0;
+
+	  wdata_q       <= 32'hxxxx_xxxx;
+	  be_q          <= 8'hxx;
        end
      else
        begin
@@ -285,17 +291,17 @@ module sdram
 
 	  // Default values
 	  dram_ba       <= 2'bxx;
-	  dram_dqm      <= 2'b11;
+	  dram_dqm      <= 2'b00;
 	  dram_d        <= 16'hxxxx;
 	  dram_cmd      <= cmd_nop;
 
-	  rack0		<= rack0 >> 1;
-	  wack0         <= 1'b0;
-	  rack1		<= rack1 >> 1;
-	  wack1         <= 1'b0;
-
 	  dram_d_en     <= 1'b1; // Don't float except during read
 
+	  rack0       <= 1'b0;
+	  wack0       <= 1'b0;
+	  rack1       <= 1'b0;
+	  wack1       <= 1'b0;
+
 	  if (state == st_reset || state == st_idle)
 	    op_cycle <= 1'b0;
 	  else
@@ -341,12 +347,11 @@ module sdram
 		   4'b1???:
 		     begin
 			// Begin port 0 transaction
-			dram_cmd    <= cmd_act;
-			dram_a      <= a0[24:12];
-			dram_ba     <= a0[11:10];
-			col_addr    <= a0[11:2];
-			be_q        <= 1'b1 << a0[1:0];
-			port        <= 1'b0;
+			dram_cmd     <= cmd_act;
+			dram_a       <= a0[24:12];
+			dram_ba      <= a0[11:10];
+			col_addr     <= a0[11:2];
+			be_q         <= 1'b1 << a0[1:0];
 			if ( wrq0 )
 			  begin
 			     state   <= st_wr;
@@ -355,19 +360,19 @@ module sdram
 			  end
 			else
 			  begin
-			     state  <= st_rd;
-			     rack0[t_rcd+t_cl+3] <= 1'b1;
+			     state   <= st_rd;
+			     rack0   <= 1'b1;
+			     rvalid0 <= 1'b0;
 			  end
 		     end
 		   4'b010?:
 		     begin
 			// Begin port 1 transaction
-			dram_cmd    <= cmd_act;
-			dram_a      <= a1[24:12];
-			dram_ba     <= a1[11:10];
-			col_addr    <= a1[11:2];
-			be_q        <= be1;
-			port        <= 1'b1;
+			dram_cmd     <= cmd_act;
+			dram_a       <= a1[24:12];
+			dram_ba      <= a1[11:10];
+			col_addr     <= a1[11:2];
+			be_q         <= be1;
 			if ( wrq1 )
 			  begin
 			     state   <= st_wr;
@@ -376,8 +381,9 @@ module sdram
 			  end
 			else
 			  begin
-			     state  <= st_rd;
-			     rack1[t_rcd+t_cl+3] <= 1'b1;
+			     state   <= st_rd;
+			     rack1   <= 1'b1;
+			     rvalid1 <= 1'b0;
 			  end
 		     end
 		   4'b0?1?, 4'b0001:
@@ -400,8 +406,10 @@ module sdram
 	      end
 	    st_rd:
 	      begin
-		 dram_d_en   <= 1'b0;		// Tristate our output
-		 dram_dqm    <= 2'b00;
+		 rack0       <= rack0;
+		 rack1       <= rack1;
+
+		 dram_d_en   <= 1'b0;		// Tristate data bus
 
 		 // Commands
 		 //
@@ -430,41 +438,59 @@ module sdram
 		   end
 		   10: begin
 		      state <= st_idle;
+		      rack0 <= 1'b0;
+		      rack1 <= 1'b0;
 		   end
 		 endcase // case (op_cycle)
 
 		 // +2 for bus turnaround latencies
+		 // Assert rvalid in the same cycle the last requested
+		 // data byte (as given by byte enables) is latched.
+
 		 if (op_cycle >= 2+t_cl+2)
 		   begin
-		      if (port == 1'b0)
+		      if (rack0)
 			begin
+			   rvalid0 <= ~|be_q[7:2];
+
 			   if (be_q[0])
 			     rd0 <= dram_q[7:0];
 			   if (be_q[1])
 			     rd0 <= dram_q[15:8];
 			end
-		      else if (op_cycle[0] ^ ((2+t_cl+2) & 1'b1))
-			begin
-			   // Odd word
-			   if (be_q[0])
-			     rd1[23:16] <= dram_q[ 7:0];
-			   if (be_q[1])
-			     rd1[31:24] <= dram_q[15:8];
-			end
-		      else
+		      if (rack1)
 			begin
-			   // Even word
-			   if (be_q[0])
-			     rd1[ 7:0] <= dram_q[ 7:0];
-			   if (be_q[1])
-			     rd1[15:8] <= dram_q[15:8];
-			end // else: !if(op_cycle[0] ^ ((t_rcd-1+t_cl+2) & 1'b1))
+			   rvalid1 <= ~|be_q[7:2];
+
+			   if (op_cycle[0] ^ ((2+t_cl+2) & 1'b1))
+			     begin
+				// Odd word
+				if (be_q[0])
+				  rd1[23:16] <= dram_q[ 7:0];
+				if (be_q[1])
+				  rd1[31:24] <= dram_q[15:8];
+			     end
+			   else
+			     begin
+				// Even word
+				if (be_q[0])
+				  rd1[ 7:0] <= dram_q[ 7:0];
+				if (be_q[1])
+				  rd1[15:8] <= dram_q[15:8];
+			     end // else: !if(op_cycle[0] ^ ((t_rcd-1+t_cl+2) & 1'b1))
+			end // if (rack1)
+
 		      be_q >>= 2;
 		   end // if (op_cycle >= 2+t_cl+2)
 	      end // case: st_rd
 
 	    st_wr:
 	      begin
+		 wack0 <= wack0;
+		 wack1 <= wack1;
+
+		 dram_dqm <= 2'b11; // Mask data bytes unless we mean it
+
 		 // Commands
 		 //
 		 // This assumes:
@@ -494,6 +520,8 @@ module sdram
 		   end
 		   10: begin
 		      state <= st_idle;
+		      wack0 <= 1'b0;
+		      wack1 <= 1'b0;
 		   end
 		 endcase // case (op_cycle)