Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Wishbone SSRAM Issue

Status
Not open for further replies.

DocJava

Newbie level 4
Newbie level 4
Joined
Mar 14, 2017
Messages
7
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
181
Hello,

I built a small SSRAM controller for my DE2i-150 board and have noted two things that are odd about memory accesses when I connected up the VGA-LCD core. I have an OpenRISC SoC ported to this board. Under normal circumstances the test program I wrote to test out the SSRAM works as expected (combination of 32-bit reads/writes and then a memcpy of an arbitrary length string followed by some verification). When the core is under a more dynamic load the behavior changes.

When I ran a separate VGA test program at the same time as the VGA core being active I noticed that writes to the frame buffer would set pixels both in a line (as expected) and randomly throughout the frame buffer (buggy behavior). The VGA clock is ~25 MHz for 640x480, the Wishbone bus is operating at 50 MHz, and the SSRAM clock is running at 100 MHz. I think this has to do with a read and a write occurring too close to one another, but cannot be sure. I ran a simulation and had some interesting results where a read (all the appropriate signals are set as if a read occurs) would seem to occur twice for every read/write (however the second read gets cut short).

The question I have for the board is whether or not the state machine I'm using is sufficient to properly handle talking to the SSRAM chip. I've heavily commented the code for the most part, so it may be educational for anyone else encountering similar issues with the SSRAM. Overall I'd like to use the SSRAM as a dedicated framebuffer.

Thanks for taking a look.

-Doc

ssram_controller.v

Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/**@file ssram_controller.v
 * This is a controller for the IS61LPS512 SSRAM chip.
 */
//=============================================================================
// Notes
//=============================================================================
//Reads and writes are delayed by 1 clock cycles.
 
//=============================================================================
// DEFINITIONS
//=============================================================================
module ssram_controller #(
    parameter ADDR_WIDTH = 21,
    parameter DATA_WIDTH = 32
)(
    //Wishbone
    //
    //Important: The wb_clk_i and ssram_clk_i signals must be in phase.
    //
    input        wb_clk_i,     // master clock input
    input        wb_rst_i,     // synchronous active high reset    
    input        ssram_clk_i,  // 100 MHz SSRAM clock
    
    //Wishbone Slave
    input  [ADDR_WIDTH-1:0] wb_adr_i,     // lower address bits
    input  [DATA_WIDTH-1:0] wb_dat_i,     // databus input
    output wire [DATA_WIDTH-1:0] wb_dat_o, // databus output
    input        wb_we_i,      // write enable input
    input        wb_stb_i,     // stobe/core select signal
    input        wb_cyc_i,     // valid bus cycle input
    output wire  wb_ack_o,     // bus cycle acknowledge output
 
    //SSRAM Signals
    inout wire [31:0] FS_DQ,
    output reg [26:0] FS_ADDR,
    output SSRAM_ADSC_N,
    output SSRAM_ADSP_N,
    output SSRAM_ADV_N,
    output [3:0] SSRAM_BE,
    output SSRAM_CLK,
    output SSRAM_GW_N,
    output SSRAM_OE_N,
    output SSRAM_WE_N,
    output SSRAM0_CE_N,
    output SSRAM1_CE_N
);   
    //=========================================================================
    // DEFINITIONS
    //=========================================================================
    localparam STATE_IDLE    = 4'b0000;
    localparam STATE_READ_1  = 4'b0001;
    localparam STATE_READ_2  = 4'b0010;
    localparam STATE_WRITE_1 = 4'b0100;
    localparam STATE_WRITE_2 = 4'b1000;
 
    //=========================================================================
    // Wishbone Bus
    //=========================================================================
    wire chipselect;
    wire write;
    wire read;
    reg [1:0] cycle_ack;
 
    //=========================================================================
    // INTERFACE
    //=========================================================================
    reg output_enable;
    reg adsp_n;
    reg adsc_n;
    reg adv_n;
    reg [3:0] be;
    reg gw_n;
    reg oe_n;
    reg we_n;
 
    //This register is set to whatever FS_DQ will be set to immediately.
    reg [31:0] write_dq;
 
    //This register contains whatever was read in STATE_READ_2.
    reg [31:0] read_dq;
    
    reg [3:0] fsm_state;
    reg [3:0] next_fsm_state;
 
    //=========================================================================
    // INITIAL
    //=========================================================================
    initial begin
        fsm_state <= STATE_IDLE;
        next_fsm_state <= STATE_IDLE;
        adsp_n <= 1'b0;
        adsc_n <= 1'b0;
        adv_n <= 1'b0;
        be <= 4'b0000;
        gw_n <= 1'b0;
        oe_n <= 1'b0;
        we_n <= 1'b0;
        cycle_ack <= 2'b00;
        read_dq <= 0;
        write_dq <= 0;
    end
    
    //=========================================================================
    // Wishbone Clock to SSRAM Clock Adapter
    //=========================================================================
    //This clock adapter is kept synchronized by the phase of both clocks.
    //They are both created from the same PLL with exactly double the clock rate.
    always @(posedge wb_clk_i or posedge wb_rst_i)
        begin
            if (wb_rst_i) begin
                write_dq <= 0;                
            end else begin
                //Set the FS_ADDR using the Wishbone clock since it will use
                //a Wishbone wb_adr_i and wb_dat_i (for writes). For reads the
                //FS_ADDR will still be used but the output shall be available
                //directly from FS_DQ.
                FS_ADDR[26:0] <= {5'b0_0000, wb_adr_i[19:0], 2'b00};
                write_dq <= wb_dat_i;                
            end
        end
 
    //=========================================================================
    // SSRAM State Machine
    //=========================================================================    
    //This block changes the state of the finite state machine.
    //This block executes at 100 MHz.
    always @(posedge ssram_clk_i or posedge wb_rst_i) 
        begin
            if (wb_rst_i) begin
                //Begin in the IDLE state.
                fsm_state <= STATE_IDLE;
                read_dq <= 0;
            end else begin
 
                if (fsm_state == STATE_READ_2 ||
                    fsm_state == STATE_WRITE_2) begin
                    if (fsm_state == STATE_READ_2)
                        read_dq <= FS_DQ; 
                    cycle_ack <= 2'b01;
                end else begin
                    //This only works because the SDRAM clock is exactly
                    //twice as fast as the Wishbone clock. Also, the cycle_ack
                    //only gets a one shifted onto it if its the end of an operation.
                    //This way there is a guarantee of when a one will be seen.
                    if ((cycle_ack[0] == 1'b0) &&
                        (cycle_ack[1] == 1'b1)) begin
                        //Do not extend the ack since its already
                        //been extended once. Allow a zero to be
                        //shifted onto the cycle_ack register.
                        cycle_ack <= {cycle_ack[0], 1'b0};
                    end else if ((cycle_ack[0] == 1'b1) &&
                                 (cycle_ack[1] == 1'b0)) begin
                        //Extend the ack by one cycle by shifting
                        cycle_ack <= {cycle_ack[0], 1'b0};
                    end else begin
                        //Under normal circumstances just shift
                        //a zero onto the cycle_ack register.
                        cycle_ack <= {cycle_ack[0], 1'b0};
                    end            
                end
 
                //Update the state of the state machine.
                fsm_state <= next_fsm_state;
            end
        end
 
    //This block executes the finite state machine.
    //The FSM operates at 100 MHz.
    //Notes:
    //  cycle_ack is set in the SDRAM clock domain
    //  so it must be valid during the subsequent Wishbone clock
    //  therefore it should be a shift register instead of just
    //  a normal register. The number of bits equals the number of clocks
    //  that the status is kept valid.
    always @*
        begin
            next_fsm_state = fsm_state;
 
            //Restore some values
            adsp_n = 1'b1;
            adsc_n = 1'b1;
            adv_n = 1'b0;
            we_n = 1'b0;
            oe_n = 1'b0;
            gw_n = 1'b1;
            be = 4'b0000;
                
            case (fsm_state)
                STATE_IDLE:
                    begin                        
                        //Reads take precedence over writes
                        if (read) begin
                            next_fsm_state = STATE_READ_1;                            
                        end else if (write) begin
                            next_fsm_state = STATE_WRITE_1;
                        end
                    end
                STATE_READ_1:
                    begin
                        //This should be sufficient to start a read-burst
                        //transaction with the memory chip.
                        adsp_n = 1'b0;
                        oe_n = 1'b0;
                        adsc_n = 1'b0;                        
                be = 4'b0000;
                        gw_n = 1'b1;
 
                        //Finish the read before changing states.
                        next_fsm_state = STATE_READ_2;                    
                    end
                STATE_READ_2:
                    begin
                        adsp_n = 1'b1;
                        adv_n = 1'b1;
                        adsc_n = 1'b1;
                        oe_n = 1'b0;
                        we_n = 1'b1;                        
                        be = 4'b0000;
                        gw_n = 1'b1;                        
 
                        next_fsm_state = STATE_IDLE;
                    end
                STATE_WRITE_1:
                    begin
                        //This should be sufficient to start a write-burst
                        //transaction with the memory chip.
                        be = 4'b1111;
                        adsp_n = 1'b1;
                        adsc_n = 1'b0;
                        oe_n = 1'b1;    //Output Enable N High
                        we_n = 1'b0;    //BWE Low
                        gw_n = 1'b0;
 
                        //cycle_ack <= {cycle_ack[0], 1'b0};
                        
                        //Finish the write before changing states.
                        next_fsm_state = STATE_WRITE_2;
                    end
                STATE_WRITE_2:
                    begin
                        be = 4'b1111;
                        adsp_n = 1'b1;
                        adsc_n = 1'b0;
                        oe_n = 1'b1;    //Output Enable N High
                        we_n = 1'b0;    //BWE Low                       
                        gw_n = 1'b0;
 
                        next_fsm_state = STATE_IDLE;
                    end
                 default:
                    begin
                        be = 4'b1111;
                        adsp_n = 1'b1;
                        adsc_n = 1'b0;
                        oe_n = 1'b1;    //Output Enable N High
                        we_n = 1'b0;    //BWE Low                       
                        gw_n = 1'b1;
 
                        next_fsm_state = STATE_IDLE;
                    end
            endcase
        end
    
 
    //Only assign chip select when core select and cycle are asserted at the same time.
    assign chipselect = wb_stb_i && wb_cyc_i;
 
    //Only assign write if the chip is selected and write enable is enabled.
    assign write = chipselect && wb_we_i;
 
    //Only assign read if the chip is selected and read enable is enabled.
    assign read = chipselect && ~wb_we_i;
 
    //Only assign ACK when the chip is selected and the cycle is complete.
    //This version of the code triggers either on cycle_ack or a shifted cycle_ack.
    assign wb_ack_o = chipselect && (cycle_ack[1] || cycle_ack[0]);
 
    //Assign clock
    assign SSRAM_CLK = ssram_clk_i;
 
    //This assignment takes care of the contents of ADDR
    //by automatically switching between read and write addresses
    //depending on the state of the FSM.
    //assign FS_ADDR[21:2] = (fsm_state == STATE_READ_1 || fsm_state == STATE_READ_2) ? wb_adr_i[19:0] : wb_adr_i[19:0];
    //assign FS_ADDR[26:0] = {5'b0_0000, wb_adr_i[19:0], 2'b00};
 
    //This assignment takes care of the contents of DQ
    //by automatically switching between Z and wr_dat_i depending
    //on the state of the FSM.
    //assign FS_DQ = (fsm_state == STATE_READ_1 || fsm_state == STATE_READ_2) ? 32'bZ : wb_dat_i;
 
    //DEBUG: Remove this assignment. Its just to test whether or not this fixes the output not enabled issue during build.
    assign FS_DQ = write ? write_dq : 32'bZ;
 
    //This assignment takes care of the output to the Wishbone bus at all times.
    //assign wb_dat_o = FS_DQ;
    assign wb_dat_o = read_dq;
 
    //Each SSRAM chip provides approximately 2 MiB of SSRAM.
    //Chip 0 uses the value of the highest address bit so that it
    //is not selected at the same time as chip 1.
    assign SSRAM0_CE_N = (fsm_state == STATE_READ_1 || fsm_state == STATE_READ_2) ? wb_adr_i[20] : 
        ((fsm_state == STATE_WRITE_1 || fsm_state == STATE_WRITE_2) ? wb_adr_i[20] : 1'b1);
    
    //Chip 1 negates the highest address bit so that it is
    //not selected at the same time as chip 0.
    assign SSRAM1_CE_N = (fsm_state == STATE_READ_1 || fsm_state == STATE_READ_2) ? ~wb_adr_i[20] :
        ((fsm_state == STATE_WRITE_1 || fsm_state == STATE_WRITE_2) ? ~wb_adr_i[20] : 1'b1);
 
    //Assign the byte enable (in the datasheet this is
    //negated) for an entire word to be written.
    assign SSRAM_BE[3:0] = be[3:0];
 
    //Synchronous Burst Address Advance
    assign SSRAM_ADV_N = adv_n;
 
    //Synchronous Processor Address Status
    assign SSRAM_ADSP_N = adsp_n;
 
    //Synchronous Controller Address Status
    assign SSRAM_ADSC_N = adsc_n;
 
    //Synchronous Global Write Enable
    assign SSRAM_GW_N = gw_n;
 
    //Output Enable
    assign SSRAM_OE_N = oe_n;
 
    //Synchronous Byte Write Enable
    assign SSRAM_WE_N = we_n;
    
endmodule



ssram_controller_tb.v

Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
`timescale 1ns/1ns
 
module ssram_controller_tb;
    reg test_clk;
    reg test_ssram_clk;
    reg test_reset;
 
    wire [31:0] FS_DQ;
    wire [26:0] FS_ADDR;
    wire SSRAM_ADSC_N;
    wire SSRAM_ADSP_N;
    wire SSRAM_ADV_N;
    wire [3:0] SSRAM_BE;
    wire SSRAM_CLK;
    wire SSRAM_GW_N;
    wire SSRAM_OE_N;
    wire SSRAM_WE_N;
    wire SSRAM0_CE_N;
    wire SSRAM1_CE_N;
 
    wire wb_clk;
    wire wb_rst;
    wire ssram_clk;
    reg [20:0] wb_adr_i;
    reg [31:0] wb_dat_i;
    wire [31:0] wb_dat_o;
    reg wb_we_i;
    reg wb_stb_i;
    reg wb_cyc_i;
    wire wb_ack_o;
    
    initial
        begin: CLOCK_INITIALIZATION
            test_clk = 1'b0;
            test_ssram_clk = 1'b0;
        end
 
    always
        begin: CLOCK_GENERATOR_SSRAM
            //For testing make the SSRAM clock twice as fast
            #25 test_ssram_clk = !test_ssram_clk;
        end
    always
        begin: CLOCK_GENERATOR
            //For testing make the main clock half speed.
            #50 test_clk = !test_clk;            
        end
 
    assign wb_clk = test_clk;
    assign ssram_clk = test_ssram_clk;
    assign wb_rst = test_reset;
 
    initial
        begin
            //FS_ADDR = 21'b0;
            //FS_DQ = 32'h0;
            wb_dat_i = 32'h0;
            wb_adr_i = 21'b0;
            wb_we_i = 0;
            wb_cyc_i = 0;
            wb_stb_i = 0;
            test_reset      = 0;       
            #50
            test_reset      = 1;
            #50
            test_reset      = 0;
 
            // Test a read
            #50
            //FS_DQ = 32'h32EFDCAB;
            wb_adr_i = 21'b1_0000_1100_0000_1000_1000;
            wb_we_i = 0;
            wb_cyc_i = 1;
            wb_stb_i = 1;
                        
            #250
            wb_we_i = 1;
            wb_cyc_i = 0;
            wb_stb_i = 0;
 
            #500
            //Test a write
            wb_adr_i = 21'b1_0000_1100_0000_1000_1000;
            wb_dat_i = 32'hABCDEF12;
            wb_we_i = 1;
            wb_cyc_i = 1;
            wb_stb_i = 1;
 
            #250
            wb_we_i = 0;
            wb_cyc_i = 0;
            wb_stb_i = 0;
        end
    
    ssram_controller dut (
        //Wishbone
        .wb_clk_i       (test_clk),
        .wb_rst_i       (test_reset),
        .ssram_clk_i    (test_ssram_clk),
        
        //Wishbone Slave
        .wb_adr_i       (wb_adr_i),
        .wb_dat_i       (wb_dat_i),
        .wb_dat_o       (wb_dat_o),
        .wb_we_i        (wb_we_i),
        .wb_stb_i       (wb_stb_i),
        .wb_cyc_i       (wb_cyc_i),
        .wb_ack_o       (wb_ack_o),
    
        //SSRAM Signals
        .FS_DQ           (FS_DQ),
        .FS_ADDR         (FS_ADDR),
        .SSRAM_ADSC_N    (SSRAM_ADSC_N),
        .SSRAM_ADSP_N    (SSRAM_ADSP_N),
        .SSRAM_ADV_N     (SSRAM_ADV_N),
        .SSRAM_BE        (SSRAM_BE),
        .SSRAM_CLK       (SSRAM_CLK),
        .SSRAM_GW_N      (SSRAM_GW_N),
        .SSRAM_OE_N      (SSRAM_OE_N),
        .SSRAM_WE_N      (SSRAM_WE_N),
        .SSRAM0_CE_N     (SSRAM0_CE_N),
        .SSRAM1_CE_N     (SSRAM1_CE_N)
    );
endmodule

 

My guess, and I could be wrong, you have an address latching problem. Can you insert delays...? Perhaps delay ADV by a few ns?

Can you post the SSRAM chip you have? I had a quick glance in DE2i-150 manual and it doesn't list the part there, just bus width and capacity.
 

The SSRAM part is the IS61LPS512.

Here's the datasheet for the SSRAM part. It includes read/write timing diagrams a few pages into the sheet.
**broken link removed**

-Doc
 

The SSRAM part is the IS61LPS512.

Here's the datasheet for the SSRAM part. It includes read/write timing diagrams a few pages into the sheet.
**broken link removed**

-Doc

My bad, you mentioned the chip part in your code comment.

Well that's unexpected. Different vendors have different pin definition. For ISSI SSRAM /ADV is address advance, while for Micron PSRAM /ADV is address valid (latch).

Try adjusting /ADSP and /ADSC timing. Try delaying a few ns.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top