OpenCores
URL https://opencores.org/ocsvn/s80186/s80186/trunk

Subversion Repositories s80186

[/] [s80186/] [trunk/] [fpga/] [sdram/] [SDRAMController.sv] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jamieiles
// Copyright Jamie Iles, 2017
2
//
3
// This file is part of s80x86.
4
//
5
// s80x86 is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
//
10
// s80x86 is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
//
15
// You should have received a copy of the GNU General Public License
16
// along with s80x86.  If not, see .
17
 
18
/*
19
 * Simple SDR SDRAM controller for 4Mx16x4 devices, e.g. ISSI IS45S16160G
20
 * (32MB) or 64MB variants.
21
 */
22
module SDRAMController #(parameter size = 32 * 1024 * 1024,
23
                         parameter clkf = 25000000)
24
                        (input logic clk,
25
                         input logic reset,
26
                         input logic data_m_access,
27
                         input logic cs,
28
                         /* Host interface. */
29
                         input logic [25:1] h_addr,
30
                         input logic [15:0] h_wdata,
31
                         output logic [15:0] h_rdata,
32
                         input logic h_wr_en,
33
                         input logic [1:0] h_bytesel,
34
                         output logic h_compl,
35
                         output logic h_config_done,
36
                         /* SDRAM signals. */
37
                         output logic s_ras_n,
38
                         output logic s_cas_n,
39
                         output logic s_wr_en,
40
                         output logic [1:0] s_bytesel,
41
                         output logic [12:0] s_addr,
42
                         output logic s_cs_n,
43
                         output logic s_clken,
44
                         inout [15:0] s_data,
45
                         output logic [1:0] s_banksel);
46
 
47
localparam ns_per_clk   = (1000000000 / clkf);
48
localparam tReset       = 100000 / ns_per_clk;
49
localparam tRC          = 8;
50
localparam tRP          = 2;
51
localparam tMRD         = 2;
52
localparam tRCD         = 2;
53
localparam cas          = 2;
54
/*
55
 * From idle, what is the longest path to get back to idle (excluding
56
 * autorefresh)?  We need to know this to make sure that we issue the
57
 * autorefresh command often enough.
58
 *
59
 * tRef of 64ms for normal temperatures (< 85C).
60
 *
61
 * Need to refresh 8192 times every tRef.
62
 */
63
localparam tRef           = ((64 * 1000000) / ns_per_clk) / 8192;
64
localparam max_cmd_period = tRCD + tRP + 1;
65
localparam refresh_counter_width = $clog2(tRef);
66
 
67
/* Command truth table: CS  RAS  CAS  WE. */
68
localparam CMD_NOP        = 4'b0111;
69
localparam CMD_BST        = 4'b0110;
70
localparam CMD_READ       = 4'b0101;
71
localparam CMD_WRITE      = 4'b0100;
72
localparam CMD_ACT        = 4'b0011;
73
localparam CMD_PRE        = 4'b0010;
74
localparam CMD_REF        = 4'b0001;
75
localparam CMD_MRS        = 4'b0000;
76
 
77
localparam STATE_RESET      = 4'b0000;
78
localparam STATE_RESET_PCH  = 4'b0001;
79
localparam STATE_RESET_REF1 = 4'b0011;
80
localparam STATE_RESET_REF2 = 4'b0010;
81
localparam STATE_MRS        = 4'b0110;
82
localparam STATE_IDLE       = 4'b0111;
83
localparam STATE_ACT        = 4'b0101;
84
localparam STATE_READ       = 4'b1101;
85
localparam STATE_WRITE      = 4'b1001;
86
localparam STATE_PCH        = 4'b1000;
87
localparam STATE_AUTOREF    = 4'b1010;
88
 
89
reg [3:0] state;
90
reg [3:0] next_state;
91
 
92
reg [3:0] cmd;
93
 
94
reg [15:0] outdata /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_REGISTER=ON ; FAST_OUTPUT_ENABLE_REGISTER=ON" */;
95
reg [1:0] outbytesel;
96
 
97
wire oe = state == STATE_WRITE && timec < {{timec_width-2{1'b0}}, 2'd2} /* synthesis ALTERA_ATTRIBUTE = "FAST_OUTPUT_ENABLE_REGISTER=ON"  */;
98
 
99
assign s_cs_n           = cmd[3];
100
assign s_ras_n          = cmd[2];
101
assign s_cas_n          = cmd[1];
102
assign s_wr_en          = cmd[0];
103
assign s_data           = oe ? outdata : {16{1'bz}};
104
assign s_bytesel        = outbytesel;
105
assign s_clken          = 1'b1;
106
 
107
/*
108
 * We support 4 banks of 8MB each, rather than interleaving one bank follows
109
 * the next.  We ignore the LSB of the address - unaligned accesses are not
110
 * supported and are undefined.
111
 */
112
wire [1:0] h_banksel;
113
wire [12:0] h_rowsel;
114
wire [12:0] col_pchg;
115
 
116
generate
117
if (size == 32 * 1024 * 1024) begin
118
    assign h_banksel            = h_addr[24:23];
119
    assign h_banksel            = h_addr[24:23];
120
    assign h_rowsel             = h_addr[22:10];
121
    assign col_pchg             = {2'b00, 1'b1, 1'b0, h_addr[9:1]};
122
end else if (size == 64 * 1024 * 1024) begin
123
    assign h_banksel            = h_addr[25:24];
124
    assign h_banksel            = h_addr[25:24];
125
    assign h_rowsel             = h_addr[23:11];
126
    assign col_pchg             = {2'b00, 1'b1, h_addr[10:1]};
127
end
128
endgenerate
129
 
130
/*
131
 * State machine counter.  Counts every cycle, resets on change of state
132
 * - once we reach one of the timing parameters we can transition again.  On
133
 * count 0 we emit the command, after that it's NOP's all the way.
134
 */
135
localparam timec_width = $clog2(tReset);
136
wire [timec_width - 1:0] timec;
137
 
138
Counter         #(.count_width(timec_width),
139
                  .count_max(tReset))
140
                TimecCounter(.clk(clk),
141
                             .count(timec),
142
                             .reset(state != next_state | reset));
143
 
144
/*
145
 * Make sure that we refresh the correct number of times per refresh period
146
 * and have sufficient time to complete any transaction in progress.
147
 */
148
wire [refresh_counter_width - 1:0] refresh_count;
149
wire autorefresh_counter_clr = state == STATE_AUTOREF && timec == tRC - 1;
150
 
151
Counter         #(.count_width(refresh_counter_width),
152
                  .count_max(tRef - max_cmd_period))
153
                RefreshCounter(.clk(clk),
154
                               .count(refresh_count),
155
                               .reset(autorefresh_counter_clr | reset));
156
 
157
wire autorefresh_pending = refresh_count == tRef[refresh_counter_width - 1:0] - max_cmd_period;
158
 
159
always_comb begin
160
    next_state = state;
161
    case (state)
162
    STATE_RESET: begin
163
        if (timec == tReset[timec_width - 1:0] - 1)
164
            next_state = STATE_RESET_PCH;
165
    end
166
    STATE_RESET_PCH: begin
167
        if (timec == tRP - 1)
168
            next_state = STATE_RESET_REF1;
169
    end
170
    STATE_RESET_REF1: begin
171
        if (timec == tRC - 1)
172
            next_state = STATE_RESET_REF2;
173
    end
174
    STATE_RESET_REF2: begin
175
        if (timec == tRC - 1)
176
            next_state = STATE_MRS;
177
    end
178
    STATE_MRS: begin
179
        if (timec == tMRD - 1)
180
            next_state = STATE_IDLE;
181
    end
182
    STATE_IDLE: begin
183
        /*
184
         * If we have a refresh pending then make sure we handle that
185
         * first!
186
         */
187
        if (!h_compl && autorefresh_pending)
188
            next_state = STATE_AUTOREF;
189
        else if (!h_compl && cs && data_m_access)
190
            next_state = STATE_ACT;
191
    end
192
    STATE_ACT: begin
193
        if (timec == tRCD - 1)
194
            next_state = h_wr_en ? STATE_WRITE : STATE_READ;
195
    end
196
    STATE_WRITE: begin
197
        if (timec == tRP)
198
            next_state = STATE_IDLE;
199
    end
200
    STATE_READ: begin
201
        if (timec == cas)
202
            next_state = STATE_IDLE;
203
    end
204
    STATE_AUTOREF: begin
205
        if (timec == tRC - 1)
206
            next_state = STATE_IDLE;
207
    end
208
    default: begin
209
        next_state = STATE_IDLE;
210
    end
211
    endcase
212
 
213
    if (reset)
214
        next_state = STATE_RESET;
215
end
216
 
217
always_ff @(posedge clk or posedge reset) begin
218
    if (reset) begin
219
        cmd <= CMD_NOP;
220
        s_addr <= 13'b0;
221
        s_banksel <= 2'b00;
222
    end else begin
223
        cmd <= CMD_NOP;
224
        s_addr <= 13'b0;
225
        s_banksel <= 2'b00;
226
        if (state != next_state) begin
227
            case (next_state)
228
            STATE_RESET_PCH: begin
229
                cmd <= CMD_PRE;
230
                s_addr <= 13'b10000000000;
231
                s_banksel <= 2'b11;
232
            end
233
            STATE_RESET_REF1: begin
234
                cmd <= CMD_REF;
235
            end
236
            STATE_RESET_REF2: begin
237
                cmd <= CMD_REF;
238
            end
239
            STATE_MRS: begin
240
                cmd <= CMD_MRS;
241
                s_banksel <= 2'b00;
242
                /* Burst length 2, CAS 2. */
243
                s_addr <= 13'b1000100000;
244
            end
245
            STATE_ACT: begin
246
                cmd <= CMD_ACT;
247
                s_banksel <= h_banksel;
248
                s_addr <= h_rowsel;
249
            end
250
            STATE_WRITE: begin
251
                cmd <= CMD_WRITE;
252
                /* Write with autoprecharge. */
253
                s_addr <= col_pchg;
254
                s_banksel <= h_banksel;
255
            end
256
            STATE_READ: begin
257
                cmd <= CMD_READ;
258
                /* Read with autoprecharge. */
259
                s_addr <= col_pchg;
260
                s_banksel <= h_banksel;
261
            end
262
            STATE_AUTOREF: begin
263
                cmd <= CMD_REF;
264
            end
265
            default: ;
266
            endcase
267
        end
268
    end
269
end
270
 
271
always_ff @(posedge clk or posedge reset) begin
272
    if (reset)
273
        h_rdata <= 16'b0;
274
    else
275
        h_rdata <= state == STATE_READ && timec == cas ? s_data : 16'b0;
276
end
277
 
278
always_ff @(posedge clk or posedge reset)
279
    if (reset)
280
        h_compl <= 1'b0;
281
    else
282
        h_compl <=  ((state == STATE_READ && timec == cas) ||
283
                     (state == STATE_WRITE && timec == tRP));
284
 
285
always_ff @(posedge clk) begin
286
    if (state == STATE_IDLE) begin
287
        outdata <= h_wdata[15:0];
288
        outbytesel <= h_wr_en ? ~h_bytesel[1:0] : 2'b00;
289
    end
290
end
291
 
292
always_ff @(posedge clk or posedge reset)
293
    if (reset)
294
        h_config_done <= 1'b0;
295
    else if (state == STATE_IDLE)
296
        h_config_done <= 1'b1;
297
 
298
always_ff @(posedge clk)
299
    state <= next_state;
300
 
301
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.