Skip to content

Commit

Permalink
Change sdram to use a level-triggered command.
Browse files Browse the repository at this point in the history
This addresses issue pmezydlo#10, where commands would be lost if they occured
during the refresh cycle, by adding an explicit ACK output that
indicates that the controller has started on the read or write.

It still fails the sdram-test, but actually seems to be almost working.
  • Loading branch information
osresearch committed Jul 10, 2018
1 parent ae0ebf4 commit 402d3d0
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 80 deletions.
28 changes: 28 additions & 0 deletions components/pulsestretch.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Stretch a pulse for a long time
*/
module pulsestretch(
input clk,
input in,
output out
);

parameter LENGTH = 8;

reg [LENGTH-1:0] counter = 0;

always @(posedge clk)
begin
if (in) begin
counter <= 1;
out <= 1;
end else
if (counter != 0) begin
counter <= counter + 1;
out <= 1;
end else begin
out <= 0;
end
end

endmodule
43 changes: 24 additions & 19 deletions components/sdram_controller.v
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ module sdram_controller (
input rd_enable,
output rd_ready,

output ack,
output busy,
input rst_n,
input clk,

// debuggin
output [7:0] command_out,
output [4:0] state_out,

output [SDRADDR_WIDTH-1:0] addr,
output [BANK_WIDTH-1:0] bank_addr,
inout [7:0] data,
Expand Down Expand Up @@ -98,9 +103,8 @@ reg [9:0] refresh_cnt;

reg [7:0] command;
reg [4:0] state;

reg wr_enable_prev;
reg rd_enable_prev;
assign state_out = state;
assign command_out = command;

reg [7:0] command_nxt;
reg [3:0] state_cnt_nxt;
Expand Down Expand Up @@ -138,15 +142,10 @@ always @ (posedge clk)
wr_data_r <= 8'b0;
rd_data_r <= 8'b0;
busy <= 1'b0;
wr_enable_prev <= 1'b0;
rd_enable_prev <= 1'b0;
end
else
begin

wr_enable_prev <= wr_enable;
rd_enable_prev <= rd_enable;

state <= next;
command <= command_nxt;

Expand Down Expand Up @@ -187,7 +186,7 @@ always @ (posedge clk)


/* Handle logic for sending addresses to SDRAM based on current state*/
always @*
always @ (posedge clk)
begin
if (state[4])
data_mask_r <= 1'b0;
Expand Down Expand Up @@ -237,33 +236,38 @@ begin
end

// Next state logic
always @*
always @(posedge clk)
begin
state_cnt_nxt = 4'd0;
command_nxt = CMD_NOP;

if (state == IDLE)
// Monitor for refresh or hold
if (refresh_cnt >= CYCLES_BETWEEN_REFRESH)
begin
next = REF_PRE;
command_nxt = CMD_PALL;
end
else if (rd_enable && !rd_enable_prev)
if (rd_enable)
begin
ack <= 1;
next = READ_ACT;
command_nxt = CMD_BACT;
end
else if (wr_enable && !wr_enable_prev)
else if (wr_enable)
begin
ack <= 1;
next = WRIT_ACT;
command_nxt = CMD_BACT;
end
else if (refresh_cnt >= CYCLES_BETWEEN_REFRESH)
begin
ack <= 0;
next = REF_PRE;
command_nxt = CMD_PALL;
end
else
begin
// HOLD
next = IDLE;
ack <= 0;
end
else
else begin
ack <= 0;
if (!state_cnt)
case (state)
// INIT ENGINE
Expand Down Expand Up @@ -372,6 +376,7 @@ begin
next = state;
command_nxt = command;
end
end
end

endmodule
4 changes: 3 additions & 1 deletion examples/sdram/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
PROJ = sdram
SRC += top.v
SRC += ../../components/gpmc-sync.v
SRC += ../../components/doublebuf.v
SRC += ../../components/pulsestretch.v
SRC += ../../components/sdram_controller.v

all: $(PROJ).bin
all: $(PROJ).bin $(PROJ).timing
include ../Makefile.beaglewire
198 changes: 138 additions & 60 deletions examples/sdram/top.v
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,139 @@ module top( input clk,
output sdram_ras,
output sdram_cas);

parameter ADDR_WIDTH = 5;
parameter ADDR_WIDTH = 4;
parameter DATA_WIDTH = 16;
parameter RAM_DEPTH = 1 << ADDR_WIDTH;
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH];

reg oe;
reg we;
reg cs;
wire[ADDR_WIDTH-1:0] addr;
wire sys_clk = clk; // not clk_200 for now

reg oen;
reg wen;
reg csn;
reg [ADDR_WIDTH-1:0] gpmc_addr;
reg [DATA_WIDTH-1:0] data_out;
wire [DATA_WIDTH-1:0] data_in;
reg [DATA_WIDTH-1:0] data_in;

reg [24:0] sd_addr;
reg [7:0] sd_rd_data;
reg [7:0] sd_wr_data;
reg sd_wr_enable;
reg sd_rd_enable;
reg sd_busy;
reg sd_ack;
reg sd_rd_ready;
reg sd_rst;

// debugging
reg [7:0] sd_command;
reg [4:0] sd_state;


// the SDRAM doesn't respond with busy immediately, so we
// have our own busy signal until it does.
reg busy_wait = 0;
reg sd_rd_ready_stretch;
reg sd_busy_stretch;
pulsestretch #(.LENGTH(8)) stretch0(sys_clk, sd_rd_ready, sd_rd_ready_stretch);
pulsestretch #(.LENGTH(17)) stretch1(sys_clk, sd_busy, sd_busy_stretch);

always @ (posedge clk_200)

reg rd_ready = 0;
reg [7:0] rd_data = 0;

reg in_progress = 0;
reg [15:0] cmd_count = 0;
reg [15:0] last_sr = 0;
reg [15:0] rd_count = 0;

always @ (posedge sys_clk)
begin
if (!cs && !we && oe) begin
mem[addr] <= data_out;
// once the SDRAM has acknowledged our command, unset our busy flags
if (sd_ack) begin
sd_rd_enable <= 0;
sd_wr_enable <= 0;
busy_wait <= 0;
end
end

always @ (posedge clk_200)
begin
if (!cs && we && !oe) begin
mem[0][4] <= sd_rd_ready;
mem[0][1] <= sd_busy;
mem[4][7:0] <= sd_rd_data;
data_in <= mem[addr];
end else begin
data_in <= 0;
if (sd_rd_ready) begin
// new data from the SDRAM is ready; latch the ready bit
rd_ready <= 1;
rd_data <= sd_rd_data;
rd_count <= rd_count + 1;
end

if (csn) begin
in_progress <= 0;
end else
if (!wen && oen) begin
if (!in_progress)
cmd_count <= cmd_count + 1;
in_progress <= 1;

// default is to restore everything to a known state
//sd_rst <= 0;

// GPMC writes destroy any pending reads

case(gpmc_addr)
0: begin
// update the status register flags
// if both read and write are specified, only read
if (data_out[15:8] != 8'hA5)
last_sr <= data_out;
else begin
sd_rd_enable <= data_out[0];
sd_wr_enable <= data_out[1];
sd_rst <= data_out[4];

// if we are doing a read or write op, go ahead
// and set our busy flag until the SDRAM acks the command
busy_wait <= data_out[0] || data_out[1];
end
end
1: begin
sd_addr[15:0] <= data_out[15:0]; // 16 bits
end
2: begin
sd_addr[24:16] <= data_out[8:0]; // 9 bits
end
3: begin
sd_wr_data <= data_out[7:0];
end
endcase
end else
if (wen && !oen) begin
case(gpmc_addr)
0: begin
// fill in the read-side of the status register
data_in[0] <= sd_rd_enable;
data_in[1] <= sd_wr_enable;
//data_in[2] <= sd_busy_stretch;

// we are waiting for either the real busy
// or the ack to our command
data_in[2] <= sd_busy || busy_wait;

data_in[3] <= rd_ready;
data_in[4] <= sd_rst;
data_in[5] <= sd_busy;
data_in[6] <= sd_ack;
data_in[15:7] <= 0;
//data_in[15:8] <= last_sr; // cmd_count;
//data_in[15:4] <= cmd_count;
end
4: begin
// read the data and reset the rd_ready flag
rd_ready <= 0;
data_in[7:0] <= rd_data;
data_in[15:8] <= 0;
end
5: data_in <= cmd_count;
6: data_in <= last_sr;
7: data_in <= rd_count;
8: data_in <= { sd_state, sd_command };
endcase
end

end

/*
Expand Down Expand Up @@ -98,7 +202,7 @@ gpmc_sync #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH))
gpmc_controller (
.clk(clk_200),
.clk(sys_clk),

.gpmc_ad(gpmc_ad),
.gpmc_advn(gpmc_advn),
Expand All @@ -107,45 +211,15 @@ gpmc_controller (
.gpmc_oen(gpmc_oen),
.gpmc_clk(gpmc_clk),

.oe(oe),
.we(we),
.cs(cs),
.address(addr),
.oen(oen),
.wen(wen),
.csn(csn),
.address(gpmc_addr),
.data_out(data_out),
.data_in(data_in),
.data_in(data_in)
);

assign pmod1[0] = sdram_ras;
assign pmod1[1] = sdram_cas;
assign pmod1[2] = sdram_we;
assign pmod1[3] = sdram_clk;
assign pmod1[4] = sdram_dqm;
assign pmod1[7] = sdram_addr[10];

assign led = mem[0][3:0];

assign pmod2 = 8'b00000000;
assign pmod3 = 8'b00000000;
assign pmod4 = 8'b00000000;

assign sdram_clk = clk;

wire [24:0] sd_addr;
wire [7:0] sd_rd_data;
wire [7:0] sd_wr_data;
wire sd_wr_enable;
wire sd_rd_enable;
wire sd_busy;
wire sd_rd_ready;
wire sd_rst;

assign sd_addr[15:0] = mem[1];
assign sd_addr[24:16] = mem[2][8:0];
assign sd_wr_data = mem[3][7:0];

assign sd_wr_enable = mem[0][3];
assign sd_rd_enable = mem[0][2];
assign sd_rst = mem[0][0];
assign sdram_clk = sys_clk;

sdram_controller sdram_controller_1 (
.wr_addr(sd_addr),
Expand All @@ -157,9 +231,13 @@ sdram_controller sdram_controller_1 (
.rd_data(sd_rd_data),
.rd_ready(sd_rd_ready),
.busy(sd_busy),
.ack(sd_ack),

.clk(clk),
.rst_n(sd_rst),
.clk(sys_clk),
.rst_n(!sd_rst),

.state_out(sd_state),
.command_out(sd_command),

.addr(sdram_addr),
.bank_addr(sdram_bank),
Expand Down

0 comments on commit 402d3d0

Please sign in to comment.