Advertisement
Guest User

async_fifo.v

a guest
Dec 23rd, 2021
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Credits to:
  2. // https://github.com/jbush001/NyuziProcessor/blob/master/hardware/fpga/common/async_fifo.sv
  3. // https://github.com/ZipCPU/website/blob/master/examples/afifo.v
  4. //
  5. // Copyright 2011-2015 Jeff Bush
  6. //
  7. // Licensed under the Apache License, Version 2.0 (the "License");
  8. // you may not use this file except in compliance with the License.
  9. // You may obtain a copy of the License at
  10. //
  11. //     http://www.apache.org/licenses/LICENSE-2.0
  12. //
  13. // Unless required by applicable law or agreed to in writing, software
  14. // distributed under the License is distributed on an "AS IS" BASIS,
  15. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. // See the License for the specific language governing permissions and
  17. // limitations under the License.
  18. //
  19.  
  20. //
  21. // Asynchronous FIFO, with two clock domains
  22. // reset is asynchronous and is synchronized to each clock domain
  23. // internally.
  24. // NUM_ENTRIES must be a power of two and >= 2
  25. //
  26.  
  27. //`default_nettype none
  28.  
  29. // for writing and reading 2 different values into 2 different FIFO entry locations
  30. `define ENABLE_TWIN_WRITE_TEST 1
  31.  
  32. // usually enables this whenever read clock domain is faster than write clock domain
  33. `define STA_SETUP_ISSUE_WITH_READ_DOMAIN 1
  34.  
  35. module async_fifo
  36.     #(
  37.         `ifdef FORMAL
  38.             parameter WIDTH = 4,
  39.         `else
  40.             parameter WIDTH = 32,      
  41.         `endif
  42.        
  43.         parameter NUM_ENTRIES = 8
  44.     )
  45.  
  46.     (input                  write_reset,
  47.      input                  read_reset,
  48.  
  49.     // Read.
  50.     input                   read_clk,
  51.     input                   read_en,
  52.     output reg [WIDTH - 1:0]    read_data,
  53.     output                  empty,
  54.  
  55.     // Write
  56.     input                   write_clk,
  57.     input                   write_en,
  58.     output                  full,
  59.     input [WIDTH - 1:0]     write_data);
  60.  
  61.     parameter ADDR_WIDTH = $clog2(NUM_ENTRIES);
  62.  
  63.     wire [ADDR_WIDTH:0] write_ptr_sync;
  64.     reg  [ADDR_WIDTH:0] read_ptr;
  65.     reg  [ADDR_WIDTH:0] read_ptr_gray;
  66.     wire [ADDR_WIDTH:0] read_ptr_nxt;
  67.     wire [ADDR_WIDTH:0] read_ptr_gray_nxt;
  68.     wire reset_rsync;
  69.     wire [ADDR_WIDTH:0] read_ptr_sync;
  70.     reg  [ADDR_WIDTH:0] write_ptr;
  71.     reg  [ADDR_WIDTH:0] write_ptr_gray;
  72.     wire [ADDR_WIDTH:0] write_ptr_nxt;
  73.     wire [ADDR_WIDTH:0] write_ptr_gray_nxt;
  74.     wire reset_wsync;
  75.     reg [WIDTH - 1:0] fifo_data[0:NUM_ENTRIES - 1];
  76.  
  77.     `ifdef FORMAL
  78.     initial read_ptr = 0;
  79.     initial write_ptr = 0;
  80.     initial read_ptr_gray = 0;
  81.     initial write_ptr_gray = 0;
  82.     initial assume(read_en == 0);
  83.     initial assume(write_en == 0); 
  84.     `endif
  85.  
  86.     assign read_ptr_nxt = read_ptr + 1;
  87.     assign read_ptr_gray_nxt = read_ptr_nxt ^ (read_ptr_nxt >> 1);
  88.     assign write_ptr_nxt = write_ptr + 1;
  89.     assign write_ptr_gray_nxt = write_ptr_nxt ^ (write_ptr_nxt >> 1);
  90.  
  91.     //
  92.     // Read clock domain
  93.     //
  94.     synchronizer #(.WIDTH(ADDR_WIDTH+1)) write_ptr_synchronizer(
  95.         .clk(read_clk),
  96.         .reset(reset_rsync),
  97.         .data_o(write_ptr_sync),
  98.         .data_i(write_ptr_gray));
  99.  
  100.     assign empty = write_ptr_sync == read_ptr_gray;
  101.  
  102.     // For further info on reset synchronizer, see
  103.     // https://www.youtube.com/watch?v=mYSEVdUPvD8 and
  104.     // http://zipcpu.com/formal/2018/04/12/areset.html
  105.  
  106.     synchronizer #(.RESET_STATE(1)) read_reset_synchronizer(
  107.         .clk(read_clk),
  108.         .reset(read_reset),
  109.         .data_i(1'b0),
  110.         .data_o(reset_rsync));
  111.  
  112.     always @(posedge read_clk)
  113.     begin
  114.         if (reset_rsync)
  115.         begin
  116.             read_ptr <= 0;
  117.             read_ptr_gray <= 0;
  118.         end
  119.        
  120.         else if (read_en && !empty)
  121.         begin
  122.             read_ptr <= read_ptr_nxt;
  123.             read_ptr_gray <= read_ptr_gray_nxt;
  124.         end
  125.     end
  126.  
  127.     `ifdef STA_SETUP_ISSUE_WITH_READ_DOMAIN
  128.  
  129.         reg empty_previously;      
  130.         always @(posedge read_clk) empty_previously <= empty;
  131.            
  132.         reg not_empty_previously;      
  133.         always @(posedge read_clk) not_empty_previously <= ~empty_previously;
  134.  
  135.         wire [WIDTH - 1:0] data_to_be_read =
  136.                 fifo_data[read_ptr[ADDR_WIDTH-1:0]];  // passed verilator Warning-WIDTH
  137.  
  138.         reg [WIDTH - 1:0] previous_data_to_be_read, previous_previous_data_to_be_read;
  139.         always @(posedge read_clk)
  140.         begin
  141.             previous_data_to_be_read <= data_to_be_read;
  142.             previous_previous_data_to_be_read <= previous_data_to_be_read;
  143.         end
  144.        
  145.         always @(posedge read_clk)
  146.         begin
  147.             `ifdef FORMAL
  148.             if(reset_rsync) read_data <= 0;
  149.        
  150.             else
  151.             `endif
  152.            
  153.             if(not_empty_previously) read_data <= previous_previous_data_to_be_read;
  154.         end
  155.    
  156.     `else
  157.         // See https://www.edaboard.com/threads/asychronous-fifo-read_data-is-not-entirely-in-phase-with-read_ptr.400461/
  158.         always @(posedge read_clk)
  159.         begin
  160.             `ifdef FORMAL
  161.             if(reset_rsync) read_data <= 0;
  162.        
  163.             else
  164.             `endif
  165.            
  166.             if(!empty) read_data <= fifo_data[read_ptr[ADDR_WIDTH-1:0]];  // passed verilator Warning-WIDTH
  167.         end
  168.     `endif
  169.  
  170.     //
  171.     // Write clock domain
  172.     //
  173.     synchronizer #(.WIDTH(ADDR_WIDTH+1)) read_ptr_synchronizer(
  174.         .clk(write_clk),
  175.         .reset(reset_wsync),
  176.         .data_o(read_ptr_sync),
  177.         .data_i(read_ptr_gray));
  178.  
  179.  
  180.     // As for why this is needed at all, see https://math.stackexchange.com/a/4314823/625099 and
  181.     // https://www.reddit.com/r/askmath/comments/r0hp2o/simple_gray_code_question/
  182.     reg [ADDR_WIDTH:0] full_check;
  183.    
  184.     always @(posedge write_clk)
  185.     begin
  186.         if(full) full_check <= write_ptr_gray ^ read_ptr_sync;
  187.        
  188.         else full_check <= write_ptr_gray_nxt ^ read_ptr_sync;
  189.     end
  190.  
  191.     // See https://electronics.stackexchange.com/questions/596233/address-rollover-for-asynchronous-fifo       
  192.     assign full = (full_check[ADDR_WIDTH] & full_check[ADDR_WIDTH-1]) && (full_check[0 +: (ADDR_WIDTH-1)] == 0);
  193.  
  194.  
  195.     synchronizer #(.RESET_STATE(1)) write_reset_synchronizer(
  196.         .clk(write_clk),
  197.         .reset(write_reset),
  198.         .data_i(1'b0),
  199.         .data_o(reset_wsync));
  200.  
  201.     `ifdef FORMAL
  202.     integer i;
  203.     `endif
  204.  
  205.     always @(posedge write_clk)
  206.     begin
  207.         if (reset_wsync)
  208.         begin
  209.             `ifdef FORMAL
  210.                 for (i=0; i<NUM_ENTRIES; i++)
  211.                 begin
  212.                     fifo_data[i] <= {WIDTH{1'b0}};
  213.                 end    
  214.             `endif
  215.  
  216.             write_ptr <= 0;
  217.             write_ptr_gray <= 0;
  218.         end
  219.        
  220.         else if (write_en && !full)
  221.         begin
  222.             fifo_data[write_ptr[ADDR_WIDTH-1:0]] <= write_data;  // passed verilator Warning-WIDTH
  223.             write_ptr <= write_ptr_nxt;
  224.             write_ptr_gray <= write_ptr_gray_nxt;
  225.         end
  226.     end
  227.  
  228. /*See https://zipcpu.com/blog/2018/07/06/afifo.html for a formal proof of afifo in general*/
  229.  
  230. `ifdef FORMAL
  231.  
  232.     reg first_clock_had_passed;
  233.     reg first_write_clock_had_passed;
  234.     reg first_read_clock_had_passed;
  235.  
  236.     initial first_clock_had_passed = 0;
  237.     initial first_write_clock_had_passed = 0;
  238.     initial first_read_clock_had_passed = 0;
  239.  
  240.     always @($global_clock)
  241.         first_clock_had_passed <= 1;   
  242.  
  243.     // to ensure proper initial reset
  244.     initial assume(write_clk == 0);
  245.     initial assume(read_clk == 0);
  246.  
  247.     always @(posedge write_clk)
  248.         first_write_clock_had_passed <= first_clock_had_passed;
  249.  
  250.     always @(posedge read_clk)
  251.         first_read_clock_had_passed <= first_clock_had_passed;
  252.  
  253.     //always @($global_clock)
  254.         //assert($rose(reset_wsync)==$rose(reset_rsync));  // comment this out for experiment
  255. /*
  256.     always @($global_clock)
  257.     begin
  258.         if(first_write_clock_had_passed && first_read_clock_had_passed)
  259.             assert(~empty || ~full);  // ensures that only one condition is satisfied
  260.     end
  261. */
  262.     initial assume(write_reset);
  263.     initial assume(read_reset);
  264.     //always @($global_clock)
  265.     //  assume(write_reset == read_reset);  // these are system-wide reset signals affecting all clock domains
  266.    
  267.     initial assume(empty);
  268.     initial assume(!full);
  269.  
  270.     reg reset_rsync_is_done;
  271.     initial reset_rsync_is_done = 0;
  272.     initial assert(reset_rsync == 0);  
  273.  
  274.     always @(posedge read_clk)
  275.     begin
  276.         if (read_reset) reset_rsync_is_done <= 0;
  277.    
  278.         else if (reset_rsync) reset_rsync_is_done <= 1;
  279.     end
  280.  
  281.     reg reset_wsync_is_done;
  282.     initial reset_wsync_is_done = 0;   
  283.     initial assert(reset_wsync == 0);  
  284.  
  285.     always @(posedge write_clk)
  286.     begin
  287.         if (write_reset) reset_wsync_is_done <= 0;
  288.    
  289.         else if (reset_wsync) reset_wsync_is_done <= 1;
  290.     end
  291.    
  292.     always @($global_clock)
  293.     begin
  294.         if (first_clock_had_passed)
  295.         begin
  296.             if($past(reset_wsync) && ($rose(write_clk)))
  297.             begin
  298.                 assert(write_ptr == 0);
  299.                 assert(write_ptr_gray == 0);
  300.             end
  301.  
  302.             else if (!$rose(write_clk))
  303.             begin
  304.                 assume($stable(write_reset));
  305.                 assume($stable(write_en));
  306.                 assume($stable(write_data));
  307.             end    
  308.            
  309.             if($past(reset_rsync) && ($rose(read_clk)))
  310.             begin
  311.                 assert(read_ptr == 0);
  312.                 assert(read_ptr_gray == 0);
  313.                 assert(read_data == 0);
  314.                 assert(empty);
  315.             end
  316.  
  317.             else if (!$rose(read_clk))
  318.             begin
  319.                 assume($stable(read_reset));
  320.                 assume($stable(read_en));
  321.                 assert(empty == (write_ptr_sync == read_ptr_gray));
  322.                
  323.                 if(!reset_wsync && !$rose(write_clk) && !write_en) assert($stable(read_data));             
  324.             end                    
  325.         end
  326.     end
  327.    
  328.     always @(posedge write_clk)
  329.     begin
  330.         if(reset_wsync_is_done) assume(write_data != 0);  // for easier debugging
  331.     end
  332.    
  333. `endif
  334.  
  335. /*The following is a fractional clock divider code*/
  336.  
  337. `ifdef FORMAL
  338.  
  339.     /*
  340.     if f_wclk_step and f_rclk_step have different value, how do the code guarantee that it will still generate two different clocks, both with 50% duty cycle ?
  341.     This is a fundamental oscillator generation technique.
  342.     Imagine a table, indexed from 0 to 2^N-1, filled with a square wave
  343.     If you stepped through that table one at a time, and did a lookup, the output would be a square wave
  344.     If you stepped through it two at a time--same thing
  345.     Indeed, you might imagine the square wave going on for infinity as the table replicates itself time after time, and that the N bits used to index it are only the bottom N--the top bits index which table--but they become irrelevant since we are only looking for a repeating waveform
  346.     Hence, no matter how fast you step as long as it is less than 2^(N-1), you'll always get a square wave
  347.  
  348.     http://zipcpu.com/blog/2017/06/02/generating-timing.html
  349.     http://zipcpu.com/dsp/2017/07/11/simplest-sinewave-generator.html
  350.     http://zipcpu.com/dsp/2017/12/09/nco.html
  351.     */ 
  352.  
  353.     localparam  F_CLKBITS=5;
  354.     wire    [F_CLKBITS-1:0] f_wclk_step, f_rclk_step;
  355.  
  356.     assign  f_wclk_step = $anyconst;
  357.     assign  f_rclk_step = $anyconst;
  358.  
  359.     always @(*)
  360.         assume(f_wclk_step != 0);
  361.     always @(*)
  362.         assume(f_rclk_step != 0);
  363.     always @(*)
  364.         assume(f_rclk_step != f_wclk_step); // so that we have two different clock speed
  365.        
  366.     reg [F_CLKBITS-1:0] f_wclk_count, f_rclk_count;
  367.  
  368.     always @($global_clock)
  369.         f_wclk_count <= f_wclk_count + f_wclk_step;
  370.     always @($global_clock)
  371.         f_rclk_count <= f_rclk_count + f_rclk_step;
  372.  
  373.     always @(*)
  374.     begin
  375.         assume(write_clk == gclk_w);
  376.         assume(read_clk == gclk_r);
  377.         cover(write_clk);
  378.         cover(read_clk);
  379.     end
  380.  
  381.     wire gclk_w, gclk_r;
  382.     wire enable_in_w, enable_in_r;
  383.  
  384.     assign enable_in_w = $anyseq;
  385.     assign enable_in_r = $anyseq;
  386.  
  387.     clock_gate cg_w (.gclk(gclk_w), .clk(f_wclk_count[F_CLKBITS-1]), .enable_in(enable_in_w));
  388.  
  389.     clock_gate cg_r (.gclk(gclk_r), .clk(f_rclk_count[F_CLKBITS-1]), .enable_in(enable_in_r));
  390.  
  391. `endif
  392.  
  393.    
  394. `ifdef FORMAL
  395.    
  396.     /* twin-write test */
  397.     // write two pieces of different data into the asynchronous fifo
  398.     // then read them back from the asynchronous fifo
  399.    
  400.     wire [WIDTH - 1:0] first_data;
  401.     wire [WIDTH - 1:0] second_data;
  402.    
  403.     assign first_data = $anyconst;
  404.     assign second_data = $anyconst;
  405.    
  406.     reg first_data_is_written;
  407.     reg first_data_is_read;
  408.     reg second_data_is_written;
  409.     reg second_data_is_read;
  410.    
  411.     initial first_data_is_read = 0;
  412.     initial second_data_is_read = 0;
  413.     initial first_data_is_written = 0;
  414.     initial second_data_is_written = 0;
  415.    
  416.     always @(*) assume(first_data > NUM_ENTRIES);
  417.     always @(*) assume(second_data > NUM_ENTRIES);
  418.     always @(*) assume(first_data != second_data);
  419.  
  420.     reg [ADDR_WIDTH:0] first_address;
  421.     reg [ADDR_WIDTH:0] second_address;
  422.    
  423.     always @(posedge write_clk) assume(first_address != second_address);
  424.    
  425.     always @(posedge write_clk)
  426.     begin
  427.         if(reset_wsync)
  428.         begin
  429.             first_data_is_written <= 0;
  430.             second_data_is_written <= 0;
  431.         end
  432.    
  433.         else if(write_en && !full && !first_data_is_written)
  434.         begin
  435.             assume(write_data == first_data);
  436.             first_data_is_written <= 1;
  437.             first_address <= write_ptr;
  438.         end
  439.        
  440.         else if(write_en && !full && !second_data_is_written)
  441.         begin
  442.             assume(write_data == second_data);
  443.             second_data_is_written <= 1;
  444.             second_address <= write_ptr;   
  445.         end
  446.     end
  447.  
  448.     always @($global_clock)
  449.     begin
  450.         if(first_clock_had_passed && ($rose(write_clk)))
  451.         begin
  452.             if($past(reset_wsync))
  453.             begin
  454.                 assert(first_data_is_written == 0);
  455.                 assert(second_data_is_written == 0);
  456.             end
  457.        
  458.             else if($past(write_en) && !$past(full) && !$past(first_data_is_written))
  459.             begin
  460.                 assert(first_data_is_written == 1);
  461.                 assert(first_address == $past(write_ptr));
  462.                 assert($past(first_data) == fifo_data[first_address]);
  463.             end
  464.            
  465.             else if($past(write_en) && !$past(full) && !$past(second_data_is_written))
  466.             begin
  467.                 assert(second_data_is_written == 1);
  468.                 assert(second_address == $past(write_ptr));
  469.                 assert($past(second_data) == fifo_data[second_address]);
  470.             end
  471.         end
  472.     end
  473.    
  474.  
  475.     reg [WIDTH - 1:0] first_data_read_out;
  476.     reg [WIDTH - 1:0] second_data_read_out;
  477.    
  478.     initial first_data_is_read = 0;
  479.     initial second_data_is_read = 0;
  480.  
  481.     always @(posedge read_clk)
  482.     begin
  483.         if(reset_rsync)
  484.         begin  
  485.             first_data_read_out <= 0;
  486.             second_data_read_out <= 0;
  487.             first_data_is_read <= 0;
  488.             second_data_is_read <= 0;
  489.         end
  490.  
  491.         `ifdef ENABLE_TWIN_WRITE_TEST  
  492.        
  493.             else if(read_en && !empty && first_data_is_written && !first_data_is_read && !second_data_is_read)
  494.             begin
  495.                 first_data_read_out <= read_data;
  496.                 first_data_is_read <= 1;   
  497.             end
  498.            
  499.             else if(read_en && !empty && second_data_is_written && !second_data_is_read)
  500.             begin
  501.                 second_data_read_out <= read_data;
  502.                 second_data_is_read <= 1;  
  503.             end
  504.            
  505.         `else
  506.             else begin
  507.                 first_data_read_out <= read_data;
  508.                 second_data_read_out <= read_data;
  509.                 first_data_is_read <= 1;
  510.                 second_data_is_read <= 1;
  511.             end
  512.         `endif
  513.     end
  514.  
  515.     always @($global_clock)
  516.     begin
  517.         if(first_clock_had_passed && ($rose(read_clk)))
  518.         begin
  519.             if($past(reset_rsync))
  520.             begin
  521.                 assert(first_data_is_read == 0);
  522.                 assert(second_data_is_read == 0);
  523.             end
  524.  
  525.             `ifdef ENABLE_TWIN_WRITE_TEST
  526.            
  527.                 else if($past(read_en) && !$past(empty) && $past(first_data_is_written) && !$past(first_data_is_read) && !$past(second_data_is_read))
  528.                 begin
  529.                     assert(first_data_read_out == $past(read_data));               
  530.                     assert(first_data_is_read == 1);   
  531.                 end
  532.                
  533.                 else if($past(read_en) && !$past(empty) && $past(second_data_is_written) && !$past(second_data_is_read))
  534.                 begin
  535.                     assert(second_data_read_out == $past(read_data));
  536.                     assert(second_data_is_read == 1);
  537.                 end
  538.                
  539.             `else
  540.                 else begin
  541.                     assert(first_data_read_out == $past(read_data));               
  542.                     assert(first_data_is_read == 1);   
  543.                     assert(second_data_read_out == $past(read_data));
  544.                     assert(second_data_is_read == 1);                                  
  545.                 end
  546.             `endif
  547.         end
  548.     end
  549.  
  550. `endif
  551.  
  552. `ifdef FORMAL
  553.     // mechanism needed for 'full' and 'empty' coverage check
  554.    
  555.     // writes to FIFO for many clock cycles, then
  556.     // read from FIFO for many clock cycles
  557.    
  558.     // for this particular test, we need NUM_ENTRIES to be power of 2
  559.     // since address rollover (MSB flipping) mechanism is used to check whether
  560.     // every FIFO entries had been visited at least twice
  561.     localparam CYCLES_FOR_FULL_EMPTY_CHECK = NUM_ENTRIES;
  562.    
  563.     reg [$clog2(CYCLES_FOR_FULL_EMPTY_CHECK):0] previous_write_counter_loop_around_fifo;
  564.     reg [$clog2(CYCLES_FOR_FULL_EMPTY_CHECK):0] previous_read_counter_loop_around_fifo;
  565.  
  566.     initial previous_write_counter_loop_around_fifo = 0;
  567.     initial previous_read_counter_loop_around_fifo = 0;
  568.    
  569.     always @(posedge write_clk)
  570.     begin
  571.         if(reset_wsync_is_done)
  572.             previous_write_counter_loop_around_fifo <= write_ptr;
  573.     end
  574.  
  575.     always @(posedge read_clk)
  576.     begin
  577.         if(reset_rsync_is_done)
  578.             previous_read_counter_loop_around_fifo <= read_ptr;
  579.     end
  580.  
  581.    
  582.     // initially no testing
  583.     reg test_write_en;
  584.     reg test_read_en;  
  585.     initial test_write_en = 0;
  586.     initial test_read_en = 0;
  587.    
  588.     reg [$clog2(CYCLES_FOR_FULL_EMPTY_CHECK):0] test_write_data;
  589.  
  590.     wire finished_loop_writing;
  591.     reg finished_loop_writing_previously;
  592.     initial finished_loop_writing_previously = 0;
  593.  
  594.     always @(posedge write_clk)
  595.     begin
  596.         if(reset_wsync) finished_loop_writing_previously <= 0;
  597.    
  598.         else finished_loop_writing_previously <= finished_loop_writing;
  599.     end
  600.        
  601.     assign finished_loop_writing = (~finished_loop_writing_previously) &&  // to make this a single clock pulse
  602.                     // every FIFO entries had been visited at least once
  603.                     (&previous_write_counter_loop_around_fifo);
  604.  
  605.     wire test_write_enable = $anyseq;  // for synchronizing both 'test_write_en' and 'test_write_data' signals
  606.    
  607.     always @(posedge write_clk)
  608.     begin
  609.         if(reset_wsync || finished_loop_writing)
  610.         begin
  611.             test_write_en <= 0;
  612.             test_write_data <= 0;
  613.         end
  614.        
  615.         else if(second_data_is_read)  // starts after twin-write test
  616.         begin
  617.             test_write_en <= test_write_enable;
  618.            
  619.             // for easy tracking on write test progress
  620.             test_write_data <= test_write_data + (!full && test_write_enable);
  621.         end
  622.        
  623.         else test_write_en <= 0;
  624.     end
  625.  
  626.     wire finished_loop_reading;
  627.     reg finished_loop_reading_previously;
  628.     initial finished_loop_reading_previously = 0;
  629.  
  630.     always @(posedge read_clk)
  631.     begin
  632.         if(reset_rsync) finished_loop_reading_previously <= 0;
  633.    
  634.         else finished_loop_reading_previously <= finished_loop_reading;
  635.     end
  636.  
  637.     assign finished_loop_reading = (~finished_loop_reading_previously) &&  // to make this a single clock pulse
  638.                     // every FIFO entries had been visited at least once
  639.                     (&previous_read_counter_loop_around_fifo);
  640.  
  641.     always @(posedge read_clk)
  642.     begin
  643.         if(reset_rsync || finished_loop_reading)
  644.         begin
  645.             test_read_en <= 0;
  646.         end
  647.        
  648.         else if(second_data_is_read)  // starts after twin-write test
  649.         begin
  650.             test_read_en <= $anyseq;
  651.         end
  652.        
  653.         else test_read_en <= 0;
  654.     end
  655.  
  656.     reg finished_one_loop_test;
  657.     initial finished_one_loop_test = 0;
  658.    
  659.     always @($global_clock)
  660.     begin
  661.         if(finished_one_loop_test) finished_one_loop_test <= 0;
  662.        
  663.         else if(finished_loop_reading) finished_one_loop_test <= 1;
  664.     end
  665.  
  666.     localparam TOTAL_NUM_OF_LOOP_TESTS = 2;  // write and read operations occur concurrently for two FIFO loops
  667.     reg [$clog2(TOTAL_NUM_OF_LOOP_TESTS):0] num_of_loop_tests_done;
  668.     initial num_of_loop_tests_done = 0;
  669.    
  670.     always @($global_clock)
  671.     begin
  672.         num_of_loop_tests_done <= num_of_loop_tests_done + (finished_one_loop_test);
  673.     end
  674.  
  675.     always @(posedge write_clk)
  676.     begin
  677.         if(test_write_en)
  678.         begin
  679.             assume(write_en);
  680.             assume(write_data == test_write_data);
  681.         end
  682.        
  683.         else if(second_data_is_written)  // after twin-write test, but before full/empty coverage
  684.         begin
  685.             assume(!write_en);
  686.         end
  687.     end
  688.  
  689.     always @(posedge read_clk)
  690.     begin
  691.         if(test_read_en) assume(read_en);
  692.     end
  693.  
  694.     always @(*)
  695.     begin
  696.         if(first_clock_had_passed &&  // only initial reset
  697.             (num_of_loop_tests_done <= TOTAL_NUM_OF_LOOP_TESTS))  // another reset after the initial reset
  698.         begin
  699.             assume(!write_reset);
  700.             assume(!read_reset);
  701.         end
  702.     end
  703.        
  704. `endif
  705.  
  706.  
  707. `ifdef FORMAL
  708.  
  709.     ////////////////////////////////////////////////////
  710.     //
  711.     // Some cover statements, to make sure valuable states
  712.     // are even reachable
  713.     //
  714.     ////////////////////////////////////////////////////
  715.     //
  716.  
  717.     // Make sure a reset is possible in either domain
  718.     always @(posedge write_clk)
  719.         cover(first_write_clock_had_passed && write_reset);
  720.  
  721.     always @(posedge read_clk)
  722.         cover(first_read_clock_had_passed && read_reset);
  723.  
  724.  
  725.     always @($global_clock)
  726.     if (first_clock_had_passed && reset_rsync_is_done)
  727.         cover((empty)&&(!$past(empty)));
  728.  
  729.     always @(*)
  730.     if (first_clock_had_passed && reset_wsync_is_done)
  731.         cover(full);
  732.  
  733.     always @(posedge write_clk)
  734.     if (first_write_clock_had_passed && reset_wsync_is_done)
  735.         cover((write_en)&&(full));
  736.  
  737.     always @(posedge write_clk)
  738.     if (first_write_clock_had_passed && reset_wsync_is_done)
  739.         cover($past(full)&&(!full));
  740.  
  741.     always @(posedge write_clk)
  742.         cover((full)&&(write_en));
  743.  
  744.     always @(posedge write_clk)
  745.         cover(write_en);
  746.  
  747.     always @(posedge read_clk)
  748.         cover((empty)&&(read_en));
  749.  
  750.     always @(posedge read_clk)
  751.     if (first_read_clock_had_passed && reset_rsync_is_done)
  752.         cover($past(!empty)&&($past(read_en))&&(empty));
  753.        
  754.     always @($global_clock)
  755.         cover(first_read_clock_had_passed && (num_of_loop_tests_done == TOTAL_NUM_OF_LOOP_TESTS));
  756.        
  757. `endif
  758.  
  759. endmodule
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement