by reedb » Mon Jun 29, 2009 3:12 pm
I used the following code on the FPGA side to implement SDRAM block reads and writes. It implements the following interface changes:
1. No read turnaround cycle on writes.
2. Change USB packet layout to put data at end of packet.
3. Make USB data payload a DWORD.
These changes give a factor of four speed up on block writes to the SDRAM. Just add the following code to SDRAM_Xylo-LM.v and change FX2_SDRAM.EzUSB.cpp to match:
[size=9]module xylo_sdram3(
FX2_CLK, // FIFO clock
FX2_FD, // FIFO bidirectional data
FX2_SLRD, // FIFO read strobe
FX2_SLWR, // FIFO write strobe
FX2_FLAGS, // FIFO flags
FX2_PA_2, // FPGA wants the FX2 to drive the DATA bus
FX2_PA_3, // FX2 Enable
FX2_PA_4, // FIFO_ADR lsb
FX2_PA_5, // FIFO_ADR msb
FX2_PA_6, // End of packet
FX2_PA_7, // FIFO5 ready to accept data
SDRAM_CLK, // Clock. All SDRAM input signals are sampled on the positive edge of CLK.
SDRAM_CKE, // Clock enable. Always enabled.
SDRAM_CMD, // Command input.
SDRAM_DQM, // Data bus (DQ) enable. Active low.
SDRAM_BA, // Bank select (four banks).
SDRAM_A, // Row (A0-A11) and column (A0-A7) address.
SDRAM_DQ, // Bidirectional dtata bus.
LED,
DEBUG
);
input FX2_CLK;
inout [7:0] FX2_FD;
input [2:0] FX2_FLAGS;
output FX2_SLRD;
output FX2_SLWR;
output FX2_PA_2;
output FX2_PA_3;
output FX2_PA_4;
output FX2_PA_5;
output FX2_PA_6;
input FX2_PA_7;
output SDRAM_CLK;
output SDRAM_CKE;
output [2:0] SDRAM_CMD;
output [1:0] SDRAM_BA;
output [1:0] SDRAM_DQM;
output [11:0] SDRAM_A;
inout [15:0] SDRAM_DQ;
output [1:0] LED;
output [23:0] DEBUG;
wire clk = FX2_CLK;
// FX2 outputs
wire FIFO2_DAV = FX2_FLAGS[0];
assign FX2_PA_3 = 1'b1;
// FX2 inputs
wire FIFO_RD, FIFO_WR, FIFO_PKTEND, FIFO_DATAIN_OE, FIFO_DATAOUT_OE;
wire [1:0] FIFO_ADR;
assign {FX2_PA_5, FX2_PA_4} = FIFO_ADR; // FPGA selects one of four FX2 FIFO's
wire FX2_SLRD = ~FIFO_RD; // FPGA reads from FX2
wire FX2_SLWR = ~FIFO_WR; // FPGA writes to FX2
assign FX2_PA_6 = ~FIFO_PKTEND; // FPGA indicates End of packet, FPGA is done writing
assign FX2_PA_2 = ~FIFO_DATAIN_OE; // FPGA wants the FX2 to drive the DATA bus
wire [7:0] FIFO_DATAIN = FX2_FD; // Data from FX2
wire [7:0] FIFO_DATAOUT; // Data to FX2
assign FX2_FD = FIFO_DATAOUT_OE ? FIFO_DATAOUT : 8'hZZ;
reg mem_done;
////////////////////////////////////////////////////////////////////////////////
//
// FX2 interface state machine
//
reg [2:0] FX2_state;
initial begin
FX2_state = 3'b000;
end
////////////////////////////////////////////////////////////////////////////////
//
// Count the number of bytes received from the host.
//
wire read_byte = (FX2_state==3'b001) & FIFO2_DAV;
reg [2:0] RxD_addr_reg;
always @(posedge clk) if(read_byte) RxD_addr_reg<=RxD_addr_reg+3'h1; else RxD_addr_reg<=3'h0;
////////////////////////////////////////////////////////////////////////////////
//
//
reg [7:0] DataIn [7:0];
always @(posedge clk) if(read_byte) DataIn[RxD_addr_reg] <= FIFO_DATAIN;
////////////////////////////////////////////////////////////////////////////////
//
//
wire [23:0] mem_addr = {DataIn[2],DataIn[1],DataIn[0]};
wire [15:0] mem_datain0 = {DataIn[5],DataIn[4]};
wire [15:0] mem_datain1 = {DataIn[7],DataIn[6]};
wire [15:0] mem_dataout;
wire mem_do = &RxD_addr_reg;
wire mem_rdwr = DataIn[3][0];
wire mem_cmd = DataIn[3][1];
wire mem_mode = DataIn[3][2];
always @(posedge clk)
case(FX2_state)
3'b000: if ( FIFO2_DAV) FX2_state <= 3'b001; // wait for data packet in FIFO2
3'b001: if (~FIFO2_DAV) FX2_state <= 3'b010; // wait until end of data packet
3'b010: if (mem_done)
begin
if (mem_rdwr) FX2_state <= 3'b100; // This is a host read.
else FX2_state <= 3'b000; // This is a host write, we're done
end
3'b100: FX2_state <= 3'b101; // turnaround cycle, switch to FIFO4
3'b101: FX2_state <= 3'b110; // write data to FIFO4
3'b110: FX2_state <= 3'b111; // write data to FIFO4
3'b111: FX2_state <= 3'b000;
default: FX2_state <= 3'b000;
endcase
assign FIFO_ADR = {FX2_state[2], 1'b0}; // FIFO2 or FIFO4
assign FIFO_RD = (FX2_state==3'b001);
// now write the count back
// assign FIFO_DATAOUT = cnt;
assign FIFO_WR = (FX2_state==3'b101) | (FX2_state==3'b110);
assign FIFO_PKTEND = (FX2_state==3'b111);
assign FIFO_DATAIN_OE = ~FX2_state[2];
assign FIFO_DATAOUT_OE = FIFO_WR;
assign FIFO_DATAOUT = FX2_state[0] ? mem_dataout[7:0] : mem_dataout[15:8];
////////////////////////////////////////////////////////////////////////////////
assign SDRAM_CLK = ~clk;
assign SDRAM_CKE = 1'b1;
wire [2:0] SDRAM_CMD_LOADMODE = 3'b000;
wire [2:0] SDRAM_CMD_REFRESH = 3'b001;
wire [2:0] SDRAM_CMD_PRECHARGE = 3'b010;
wire [2:0] SDRAM_CMD_ACTIVE = 3'b011;
wire [2:0] SDRAM_CMD_WRITE = 3'b100;
wire [2:0] SDRAM_CMD_READ = 3'b101;
//wire [2:0] SDRAM_CMD_TERMINATE = 3'b110;
wire [2:0] SDRAM_CMD_NOP = 3'b111;
reg [2:0] SDRAM_CMD;
// assign {SDRAM_RASn, SDRAM_CASn, SDRAM_WEn} = SDRAM_CMD;
reg [1:0] SDRAM_BA;
reg SDRAM_DQMR;
assign SDRAM_DQM[0] = SDRAM_DQMR;
assign SDRAM_DQM[1] = SDRAM_DQMR;
reg [11:0] SDRAM_A;
reg SDRAM_DQ_oe;
reg [15:0] SDRAM_DQ_out;
reg [15:0] SDRAM_DQ_in;
reg [4:0] SDRAM_state;
initial begin
SDRAM_state = 5'b00000;
end
wire SDRAM_state0 = (SDRAM_state == 5'b00000);
wire SDRAM_state_write0 = (SDRAM_state == 5'b00010);
wire SDRAM_state_write1 = (SDRAM_state == 5'b00011);
wire SDRAM_state_write = (SDRAM_state == 5'b00010) | (SDRAM_state == 5'b00011);
wire SDRAM_state_read = (SDRAM_state == 5'b01001);
wire SDRAM_state_read_done = (SDRAM_state == 5'b01100);
reg [7:0] refresh_counter;
reg refresh_now;
always @(posedge clk) refresh_counter<=refresh_counter+8'h1;
always @(posedge clk) refresh_now <= (refresh_now ? ~SDRAM_state0 : &refresh_counter);
reg mem_do_now;
always @(posedge clk) mem_do_now <= (mem_do_now ? ~(SDRAM_state0 & ~refresh_now) : mem_do);
always @(posedge clk)
case(SDRAM_state)
5'b00000: // 0x00
begin
if(refresh_now)
begin
SDRAM_CMD <= SDRAM_CMD_REFRESH;
SDRAM_state <= 5'b01101; // goto 0x0D
end
else
if(mem_do_now & mem_cmd & ~mem_mode)
begin
SDRAM_CMD <= SDRAM_CMD_PRECHARGE; // A18 high for all banks precharge
SDRAM_state <= 5'b01100; // goto 0x0C
end
else
if(mem_do_now & mem_cmd & mem_mode)
begin
SDRAM_CMD <= SDRAM_CMD_LOADMODE; // A[18:8]
SDRAM_state <= 5'b01100; // goto 0x0C
end
else
if(mem_do_now & ~mem_cmd)
begin
SDRAM_CMD <= SDRAM_CMD_ACTIVE;
SDRAM_state <= (mem_rdwr ? 5'b01000 : 5'b00001);
end
else
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b00000;
end
end
// write
5'b00001: // 0x01
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b00010;
end
5'b00010:
begin
SDRAM_CMD <= SDRAM_CMD_WRITE;
SDRAM_state <= 5'b00011;
end
5'b00011:
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b00100;
end
5'b00100:
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b00101;
end
5'b00101:
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b00000;
end
// read // 0x08
5'b01000:
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b01001;
end
5'b01001:
begin
SDRAM_CMD <= SDRAM_CMD_READ;
SDRAM_state <= 5'b01010;
end
5'b1010:
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b01011;
end
5'b01011:
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b01100;
end
5'b1100: // 0x0C
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b00000;
end
// auto-refresh
5'b01101: // 0x0D
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b01110;
end
5'b01110:
begin
SDRAM_CMD <= SDRAM_CMD_NOP; // 0x0E
SDRAM_state <= 5'b01111;
end
5'b01111:
begin
SDRAM_CMD <= SDRAM_CMD_NOP; // 0x00
SDRAM_state <= 5'b00000;
end
default:
begin
SDRAM_CMD <= SDRAM_CMD_NOP;
SDRAM_state <= 5'b00000;
end
endcase
//reg mem_done;
always @(posedge clk)
begin
if (SDRAM_state0) SDRAM_BA <= mem_addr[21:20];
SDRAM_A <= (SDRAM_state0 ? mem_addr[19:8] : {4'b0100, mem_addr[7:0]}); // precharge
SDRAM_DQMR <= ((SDRAM_state_read | SDRAM_state_write) ? 0 : 1);
SDRAM_DQ_oe <= SDRAM_state_write;
if (SDRAM_state_write0) SDRAM_DQ_out <= mem_datain1;
else SDRAM_DQ_out <= mem_datain0;
mem_done <= SDRAM_state_write1 | SDRAM_state_read_done;
if(SDRAM_state_read_done) SDRAM_DQ_in <= SDRAM_DQ;
end
assign SDRAM_DQ = (SDRAM_DQ_oe ? SDRAM_DQ_out : 16'hZZZZ);
assign mem_dataout = SDRAM_DQ_in;
////////////////////////////////////////////////////////////////////////////////
//
// Debug Port Assignments
//
// assign DEBUG = 24'b0;
assign DEBUG[15:0] = SDRAM_DQ_out;
assign DEBUG[21:16] = SDRAM_state;
assign DEBUG[22] = clk;
assign DEBUG[23] = SDRAM_state_write0;
assign LED[0] = &DataIn[3] | mem_addr[23] & mem_addr[22];
assign LED[1] = FX2_FLAGS[1] & FX2_FLAGS[2] & FX2_PA_7;
endmodule[/size]