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

Subversion Repositories nysa_sata

[/] [nysa_sata/] [trunk/] [rtl/] [generic/] [ppfifo.v] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 cospan
/*
2
Distributed under the MIT licesnse.
3
Copyright (c) 2011 Dave McCoy (dave.mccoy@cospandesign.com)
4
 
5
Permission is hereby granted, free of charge, to any person obtaining a copy of
6
this software and associated documentation files (the "Software"), to deal in
7
the Software without restriction, including without limitation the rights to
8
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
of the Software, and to permit persons to whom the Software is furnished to do
10
so, subject to the following conditions:
11
 
12
The above copyright notice and this permission notice shall be included in all
13
copies or substantial portions of the Software.
14
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
SOFTWARE.
22
*/
23
 
24
`timescale 1ns/1ps
25
 
26
//XXX: NOTE: All counts are 24bits long, this could be a parameter in the future
27
 
28
 
29
module ppfifo
30
#(parameter     DATA_WIDTH    = 8,
31
                ADDRESS_WIDTH = 4
32
)(
33
 
34
  //universal input
35
  input                             reset,
36
 
37
  //write side
38
  input                             write_clock,
39
  output reg  [1:0]                 write_ready,
40
  input       [1:0]                 write_activate,
41
  output      [23:0]                write_fifo_size,
42
  input                             write_strobe,
43
  input       [DATA_WIDTH - 1: 0]   write_data,
44
  output                            starved,
45
 
46
  //read side
47
  input                             read_clock,
48
  input                             read_strobe,
49
  output reg                        read_ready,
50
  input                             read_activate,
51
  output reg  [23:0]                read_count,
52
  output      [DATA_WIDTH - 1: 0]   read_data,
53
 
54
  output                            inactive
55
 
56
);
57
 
58
localparam FIFO_DEPTH = (1 << ADDRESS_WIDTH);
59
 
60
//Local Registers/Wires
61
assign  write_fifo_size     = FIFO_DEPTH;
62
 
63
//Write Side
64
wire                        ppfifo_ready;  // The write side only needs to
65
                                           // know were ready if we don't
66
                                           // write anything read won't start
67
wire  [ADDRESS_WIDTH: 0]    addr_in;       // Actual address to the BRAM
68
reg   [ADDRESS_WIDTH - 1: 0]write_address;
69
reg                         r_wselect;      // Select the FIFO to work with
70
reg                         write_enable;  // Enable a write to the BRAM
71
 
72
reg   [1:0]                 wcc_read_ready;// Tell read side a FIFO is ready
73
wire  [1:0]                 wcc_read_done;
74
                                            // write status of the read
75
                                            // available
76
reg                         wcc_tie_select; //because it's possible if the read
77
                                            //side is slower than the write
78
                                            //side it might be unknown which
79
                                            //side was selected first, so use
80
                                            //this signal to break ties
81
 
82
reg   [23:0]                w_count[1:0];   // save the write count for the read
83
                                            // side
84
reg                         w_empty[1:0];
85
reg                         w_reset;        //write side reset
86
reg   [4:0]                 w_reset_timeout;
87
wire                        ready;
88
 
89
//assign  r_wselect           = (write_activate == 2'b00) ? 1'b0 :
90
//                              (write_activate == 2'b01) ? 1'b0 :
91
//                              (write_activate == 2'b10) ? 1'b1 :
92
//                              reset ?                     1'b0 :
93
//                              r_wselect;
94
//                            //I know this can be shortened down but it's more
95
//                            //readible thi way
96
 
97
assign  addr_in             = {r_wselect, write_address};
98
//assign  write_enable        = (write_activate > 0) && write_strobe;
99
assign  ppfifo_ready        = !(w_reset || r_reset);
100
assign  ready               = ppfifo_ready;
101
 
102
//assign  wcc_tie_select      = (wcc_read_ready == 2'b00) ? 1'b0 :
103
//                              (wcc_read_ready == 2'b01) ? 1'b0 :
104
//                              (wcc_read_ready == 2'b10) ? 1'b1 :
105
//                              wcc_tie_select;
106
                                            // If the first FIFO is ready,
107
                                            // then both FIFOs are ready then
108
                                            // keep the first FIFO
109
 
110
//Read Side
111
wire  [ADDRESS_WIDTH: 0]    addr_out;     //Actual address to the BRAM
112
reg                         r_reset;
113
reg   [4:0]                 r_reset_timeout;
114
 
115
reg   [ADDRESS_WIDTH - 1: 0]r_address;    //Address to access a bank
116
reg                         r_rselect;     //Select a bank (Select a FIFO)
117
 
118
wire  [1:0]                 rcc_read_ready;
119
                                          // Write side says X is ready
120
reg   [1:0]                 rcc_read_done;// Tell write side X is ready
121
wire                        rcc_tie_select;
122
                                          //If there is a tie, then this will
123
                                          //break it
124
 
125
reg   [23:0]                r_size[1:0];  // Size of FX read
126
 
127
reg   [1:0]                 r_ready;      //FIFO is ready
128
reg   [1:0]                 r_wait;       //Waiting for write side to send data
129
reg   [1:0]                 r_activate;   //Controls which FIFO is activated
130
 
131
reg                         r_next_fifo;  //If both FIFOs are availalbe use this
132
 
133
reg   [1:0]                 r_pre_activate; //Used to delay the clock cycle by
134
                                            //one when the user activates the
135
                                            //FIFO
136
 
137
reg                         r_pre_strobe;
138
reg                         r_pre_read_wait;//Wait an extra cycle so the registered data has a chance to set
139
                                            //the data to be registered
140
wire  [DATA_WIDTH - 1: 0]   w_read_data;    //data from the read FIFO
141
reg   [DATA_WIDTH - 1: 0]   r_read_data;    //data from the read FIFO
142
 
143
assign  addr_out            = {r_rselect, r_address};
144
 
145
 
146
//Debug
147
wire  [23:0]                debug_f0_w_count;
148
wire  [23:0]                debug_f1_w_count;
149
 
150
wire  [23:0]                debug_f0_r_size;
151
wire  [23:0]                debug_f1_r_size;
152
 
153
//wire  [23:0]                debug_f0_r_count;
154
//wire  [23:0]                debug_f1_r_count;
155
 
156
assign  debug_f0_w_count    = w_count[0];
157
assign  debug_f1_w_count    = w_count[1];
158
 
159
assign  debug_f0_r_size     = r_size[0];
160
assign  debug_f1_r_size     = r_size[1];
161
 
162
assign  inactive            = (w_count[0] == 0) &&
163
                              (w_count[1] == 0) &&
164
                              (write_ready == 2'b11) &&
165
                              (!write_strobe);
166
 
167
 
168
assign  read_data           = (r_pre_strobe) ? w_read_data : r_read_data;
169
 
170
 
171
//Submodules
172
blk_mem #(
173
  .DATA_WIDTH(DATA_WIDTH),
174
  .ADDRESS_WIDTH(ADDRESS_WIDTH + 1)
175
) fifo0 (
176
  //Write
177
  .clka     (write_clock        ),
178
  .wea      (write_enable       ), //This may just be replaced with write activate
179
  .dina     (write_data         ),
180
  .addra    (addr_in            ),
181
 
182
  .clkb     (read_clock         ),
183
  .doutb    (w_read_data        ),
184
  .addrb    (addr_out           )
185
);
186
 
187
//W - R FIFO 0
188
cross_clock_enable ccwf0 (
189
  .rst      (reset              ),
190
  .in_en    (wcc_read_ready[0]  ),
191
 
192
  .out_clk  (read_clock         ),
193
  .out_en   (rcc_read_ready[0]  )
194
);
195
//W - R FIFO 1
196
cross_clock_enable ccwf1 (
197
  .rst      (reset              ),
198
  .in_en    (wcc_read_ready[1]  ),
199
 
200
  .out_clk  (read_clock         ),
201
  .out_en   (rcc_read_ready[1]  )
202
 
203
);
204
 
205
//W - R Tie Select
206
cross_clock_enable ccts (
207
  .rst      (reset              ),
208
  .in_en    (wcc_tie_select     ),
209
 
210
  .out_clk  (read_clock         ),
211
  .out_en   (rcc_tie_select     )
212
);
213
 
214
//R - W FIFO 0
215
cross_clock_enable ccrf0 (
216
  .rst      (reset              ),
217
  .in_en    (rcc_read_done[0]   ),
218
 
219
  .out_clk  (read_clock         ),
220
  .out_en   (wcc_read_done[0]   )
221
);
222
//R - W FIFO 1
223
cross_clock_enable ccrf1 (
224
  .rst      (reset              ),
225
  .in_en    (rcc_read_done[1]   ),
226
 
227
  .out_clk  (read_clock         ),
228
  .out_en   (wcc_read_done[1]   )
229
);
230
 
231
//R - W Reset
232
cross_clock_enable cc_starved(
233
  .rst      (reset                         ),
234
  .in_en    (!read_ready && !read_activate ),
235
 
236
  .out_clk  (write_clock                   ),
237
  .out_en   (starved                       )
238
);
239
 
240
 
241
 
242
 
243
//asynchronous logic
244
always @ (*) begin
245
  case (wcc_read_ready)
246
    2'b00: begin
247
      wcc_tie_select  = 1'b0;
248
    end
249
    2'b01: begin
250
      wcc_tie_select  = 1'b0;
251
    end
252
    2'b10: begin
253
      wcc_tie_select  = 1'b1;
254
    end
255
    default: begin
256
      wcc_tie_select  = 1'b0;
257
    end
258
  endcase
259
end
260
always @ (*) begin
261
  case (write_activate)
262
    2'b00: begin
263
      r_wselect   = 1'b0;
264
    end
265
    2'b01: begin
266
      r_wselect   = 1'b0;
267
    end
268
    2'b10: begin
269
      r_wselect   = 1'b1;
270
    end
271
    default: begin
272
      r_wselect   = 1'b0;
273
    end
274
  endcase
275
end
276
 
277
always @ (*) begin
278
  if (write_activate > 0 && write_strobe) begin
279
    write_enable  = 1'b1;
280
  end
281
  else begin
282
    write_enable  = 1'b0;
283
  end
284
end
285
//synchronous logic
286
 
287
//Reset Logic
288
always @ (posedge write_clock) begin
289
  if (reset) begin
290
    w_reset         <=  1;
291
    w_reset_timeout <=  0;
292
  end
293
  else begin
294
    if (w_reset && (w_reset_timeout < 4'h4)) begin
295
      w_reset_timeout <=  w_reset_timeout + 1;
296
    end
297
    else begin
298
      w_reset       <=  0;
299
    end
300
  end
301
end
302
 
303
always @ (posedge read_clock) begin
304
  if (reset) begin
305
    r_reset           <=  1;
306
    r_reset_timeout   <=  0;
307
  end
308
  else begin
309
    if (r_reset && (r_reset_timeout < 4'h4)) begin
310
      r_reset_timeout <= r_reset_timeout + 1;
311
    end
312
    else begin
313
      r_reset         <=  0;
314
    end
315
  end
316
end
317
 
318
//---------------Write Side---------------
319
initial begin
320
  write_address     = 0;
321
 
322
  wcc_read_ready    = 2'b00;
323
  write_ready       = 2'b00;
324
  w_reset           = 1;
325
  w_reset_timeout   = 0;
326
  write_enable      = 0;
327
  r_wselect         = 0;
328
  wcc_tie_select    = 0;
329
end
330
 
331
always @ (posedge write_clock) begin
332
  if (reset) begin
333
    write_ready     <=  0;
334
  end
335
  else if (ready) begin
336
    //Logic for the Write Enable
337
    if (write_activate[0] && write_strobe) begin
338
      write_ready[0] <=  1'b0;
339
    end
340
    if (write_activate[1] && write_strobe) begin
341
      write_ready[1] <=  1'b0;
342
    end
343
 
344
    if (!write_activate[0] && (w_count[0] == 0) && wcc_read_done[0]) begin
345
      //FIFO 0 is not accessed by the read side, and user has not activated
346
      write_ready[0]  <=  1;
347
    end
348
    if (!write_activate[1] && (w_count[1] == 0) && wcc_read_done[1]) begin
349
      //FIFO 1 is not accessed by the read side, and user has not activated
350
      write_ready[1]  <=  1;
351
    end
352
 
353
    //When the user is finished reading the ready signal might go high
354
    //I SHOULD MAKE A CONDITION WHERE THE WRITE COUND MUST BE 0
355
  end
356
end
357
 
358
always @ (posedge write_clock) begin
359
  if (reset) begin  //Asynchronous Reset
360
    wcc_read_ready  <=  2'b00;
361
    write_address   <=  0;
362
    w_count[0]      <=  24'h0;
363
    w_count[1]      <=  24'h0;
364
  end
365
  else begin
366
    if (write_activate > 0 && write_strobe) begin
367
      write_address <=  write_address + 1;
368
      if (write_activate[0]) begin
369
        w_count[0]  <=  w_count[0] + 1;
370
      end
371
      if (write_activate[1]) begin
372
        w_count[1]  <=  w_count[1] + 1;
373
      end
374
    end
375
    if (write_activate == 0) begin
376
      write_address     <=  0;
377
      if (w_count[0] > 0) begin
378
        wcc_read_ready[0]  <=  1;
379
      end
380
      if (w_count[1] > 0) begin
381
        wcc_read_ready[1]  <=  1;
382
      end
383
    end
384
    //I can't reset the w_count until the read side has indicated that it
385
    //is done but that may be mistriggered when the write side finishes
386
    //a write. So how do
387
 
388
    //Only reset the write count when the done signal has been de-asserted
389
 
390
    //Deassert w_readX_ready when we see the read has de-asserted r_readX_done
391
    if (!wcc_read_done[0]) begin
392
      //Only reset write count when the read side has said it's busy so it
393
      //must be done reading
394
      w_count[0]        <=  0;
395
      wcc_read_ready[0] <=  0;
396
    end
397
    if (!wcc_read_done[1]) begin
398
      w_count[1]        <=  0;
399
      wcc_read_ready[1] <=  0;
400
    end
401
  end
402
end
403
 
404
 
405
//---------------Read Side---------------
406
initial begin
407
  r_rselect       = 0;
408
  r_address       = 0;
409
 
410
  rcc_read_done   = 2'b00;
411
 
412
  r_size[0]       = 24'h0;
413
  r_size[1]       = 24'h0;
414
 
415
  r_wait          = 2'b11;
416
  r_ready         = 2'b00;
417
  r_activate      = 2'b00;
418
  r_pre_activate  = 0;
419
 
420
  r_next_fifo     = 0;
421
  r_reset         = 1;
422
  r_reset_timeout = 0;
423
  read_ready      = 0;
424
  r_read_data     = 32'h0;
425
  r_pre_read_wait = 0;
426
end
427
 
428
always @ (posedge read_clock) begin
429
  if (reset) begin  //Asynchronous Reset
430
    r_rselect                       <=  0;
431
    r_address                       <=  0;
432
    rcc_read_done                   <=  2'b11;
433
    read_count                      <=  0;
434
    r_activate                      <=  2'b00;
435
    r_pre_activate                  <=  2'b00;
436
    r_pre_read_wait                 <=  0;
437
 
438
    r_size[0]                       <=  24'h0;
439
    r_size[1]                       <=  24'h0;
440
 
441
    //are these signals redundant?? can I just use the done?
442
    r_wait                          <=  2'b11;
443
 
444
    r_ready                         <=  2'b00;
445
 
446
    r_next_fifo                     <=  0;
447
    r_read_data                     <=  0;
448
 
449
  end
450
  else begin
451
    r_pre_strobe                    <=  read_strobe;
452
    //Handle user enable and ready
453
    if (!read_activate && !r_pre_activate) begin
454
      //User has not activated the read side
455
 
456
      //Prepare the read side
457
      //Reset the address
458
      if (r_activate == 0) begin
459
        read_count                      <=  0;
460
        r_address                       <=  0;
461
        r_pre_read_wait                 <=  0;
462
        if (r_ready > 0) begin
463
          //This goes to one instead of activate
464
          //Output select
465
          //read_ready                  <=  1;
466
 
467
          if (r_ready[0] && r_ready[1]) begin
468
            //$display ("Tie");
469
            //Tie
470
            r_rselect                   <=  r_next_fifo;
471
            r_pre_activate[r_next_fifo] <=  1;
472
            r_pre_activate[~r_next_fifo]<=  0;
473
            r_next_fifo                 <=  ~r_next_fifo;
474
            read_count                  <=  r_size[r_next_fifo];
475
          end
476
          else begin
477
            //Only one side is ready
478
            if (r_ready[0]) begin
479
              //$display ("select 0");
480
              r_rselect                 <=  0;
481
              r_pre_activate[0]         <=  1;
482
              r_pre_activate[1]         <=  0;
483
              r_next_fifo               <=  1;
484
              read_count                <=  r_size[0];
485
            end
486
            else begin
487
              //$display ("select 1");
488
              r_rselect                 <=  1;
489
              r_pre_activate[0]         <=  0;
490
              r_pre_activate[1]         <=  1;
491
              r_next_fifo               <=  0;
492
              read_count                <=  r_size[1];
493
            end
494
          end
495
        end
496
      end
497
      //User has finished reading something
498
      else if (r_activate[r_rselect] && !r_ready[r_rselect]) begin
499
        r_activate[r_rselect]          <=  0;
500
        rcc_read_done[r_rselect]       <=  1;
501
      end
502
    end
503
    else begin
504
      if ((r_pre_activate > 0) && r_pre_read_wait) begin
505
        read_ready                      <=  1;
506
      end
507
 
508
 
509
      if (r_activate) begin
510
        read_ready                    <=  0;
511
        //User is requesting an accss
512
        //Handle read strobes
513
        //Only handle strobes when we are enabled
514
        r_ready[r_rselect]            <=  0;
515
      end
516
 
517
      //XXX: There should be a better way to handle these edge conditions
518
      if (!r_activate && r_pre_read_wait) begin
519
        r_read_data                     <=  w_read_data;
520
        r_address                       <=  r_address + 1;
521
        r_activate                      <=  r_pre_activate;
522
        r_pre_activate                  <=  0;
523
      end
524
      else if (!r_pre_read_wait) begin
525
        r_pre_read_wait                 <=  1;
526
      end
527
 
528
      if (read_strobe && (r_address < (r_size[r_rselect] + 1))) begin
529
        //Increment the address
530
        r_read_data                     <=  w_read_data;
531
        r_address                       <=  r_address + 1;
532
      end
533
      if (r_pre_strobe && !read_strobe) begin
534
        r_read_data                     <=  w_read_data;
535
      end
536
    end
537
    if (!rcc_read_ready[0] && !r_ready[0] && !r_activate[0]) begin
538
      r_wait[0]                       <=  1;
539
    end
540
    if (!rcc_read_ready[1] && !r_ready[1] && !r_activate[1]) begin
541
      r_wait[1]                       <=  1;
542
    end
543
 
544
 
545
    //Check if the write side has sent over some data
546
    if (rcc_read_ready > 0) begin
547
      if ((r_wait == 2'b11) && (rcc_read_ready == 2'b11) && (w_count[0] > 0) && (w_count[1] > 0)) begin
548
        //An ambiguous sitution that can arrise if the read side is much
549
        //slower than the write side, both sides can arrise seemingly at the
550
        //same time, so there needs to be a tie breaker
551
        //$display ("Combo breaker goes to: %h", rcc_tie_select);
552
        r_next_fifo         <= rcc_tie_select;
553
      end
554
 
555
 
556
 
557
 
558
      if (r_wait[0] && rcc_read_ready[0]) begin
559
        //$display ("write has send over data t othe 0 side");
560
        //Normally it would not be cool to transfer data over a clock domain
561
        //but the w_count[x] is stable before the write side sends over a write
562
        //strobe
563
        if (w_count[0] > 0) begin
564
          //Only enable when count > 0
565
          if ((r_activate == 0) && (!rcc_read_ready[1])) begin
566
              //$display ("select 0");
567
              r_next_fifo   <=  0;
568
          end
569
          r_size[0]         <=  w_count[0];
570
          r_ready[0]        <=  1;
571
          r_wait[0]         <=  0;
572
          rcc_read_done[0]  <=  0;
573
        end
574
      end
575
 
576
      if (r_wait[1] && rcc_read_ready[1]) begin
577
        //$display ("write has send over data t othe 1 side");
578
        //Write side has sent some data over
579
        if (w_count[1] > 0) begin
580
         if ((r_activate == 0) && (!rcc_read_ready[0])) begin
581
              //$display ("select 1");
582
              r_next_fifo   <=  1;
583
          end
584
          r_size[1]         <=  w_count[1];
585
          r_ready[1]        <=  1;
586
          r_wait[1]         <=  0;
587
          rcc_read_done[1]  <=  0;
588
        end
589
      end
590
    end
591
  end
592
end
593
 
594
endmodule

powered by: WebSVN 2.1.0

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