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 5

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

powered by: WebSVN 2.1.0

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