Commit 87fd75fd authored by Andrey Filippov's avatar Andrey Filippov
Browse files

fixed 2 more bugs in h2d/fifo control

parent 282f41b3
Loading
Loading
Loading
Loading
+34 −4
Original line number Diff line number Diff line
@@ -24,7 +24,12 @@
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
 */
`timescale 1ns/1ps

//`define CHECK_LOW_H2D_FIFO // reduce actual h2d fifo size during simulation, to test h2d_ready
/** TODO:
 1. Check nothing is left in H2D FIFO after data is sent  - it will happen after DPATp received.
 2. Make DPATp an error? It is not easy to insert 0x00000046" data FIS header before remaining data (already in FIS)
  - it may also hold fis_transmit, as maximal data fis is 4x of the FIFO size. 
*/
module  ahci_sata_layers #(
`ifdef USE_DATASCOPE
    parameter ADDRESS_BITS =         10, //for datascope
@@ -105,6 +110,9 @@ module ahci_sata_layers #(
    output  wire        txn_out,
    input   wire        rxp_in,
    input   wire        rxn_in,
    output              debug_is_data, // @clk (sata clk) - last symbol was data output
    output              debug_dmatp,  // @clk (sata clk) - received CODE_DMATP
    
`ifdef USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
    output                    datascope_clk,
@@ -142,6 +150,13 @@ module ahci_sata_layers #(
    localparam H2D_TYPE_FIS_HEAD = 1;
    localparam H2D_TYPE_FIS_LAST = 2;
    
`ifdef SIMULATION
    `ifdef CHECK_LOW_H2D_FIFO
        localparam H2D_FIFO_THRESHOLD = 4; // to test h2d_ready - will turn off frequently, much earlier than fifo almost full
    `endif
`endif
    
    
    wire               phy_ready;        // active when GTX gets aligned output
    wire               link_established; // Received 3 back-to-back non-ALIGNp 
    wire        [31:0] ll_h2d_data_in;
@@ -186,7 +201,9 @@ module ahci_sata_layers #(
    wire       [FIFO_ADDR_WIDTH:0] d2h_fill;
    wire                           d2h_nempty;
    wire                           h2d_fifo_rd = h2d_nempty && ll_strobe_out; // TODO: check latency in link.v
    wire                           h2d_fifo_wr = h2d_valid;
//    wire                           h2d_fifo_wr = h2d_valid;
//2016.12.10
    wire                           h2d_fifo_wr = h2d_valid && h2d_ready; // or should valid depend on ready in the fis_transmit?
    
    wire                           d2h_fifo_rd = d2h_valid && d2h_ready;
    wire                           d2h_fifo_wr = ll_d2h_valid || fis_over_r; // fis_over_r will push FIS end to FIFO
@@ -205,7 +222,18 @@ assign ll_h2d_last = (h2d_type_out == H2D_TYPE_FIS_LAST);
assign d2h_valid = d2h_nempty;
assign d2h_many =  |d2h_fill[FIFO_ADDR_WIDTH:3]; // 

assign h2d_ready = !h2d_fill[FIFO_ADDR_WIDTH] && !(&h2d_fill[FIFO_ADDR_WIDTH:3]);
// assign h2d_ready = !h2d_fill[FIFO_ADDR_WIDTH] && !(&h2d_fill[FIFO_ADDR_WIDTH:3]);
// 2016:12:10 sometimes overflow happened because of a BUG 
`ifdef SIMULATION
    `ifdef CHECK_LOW_H2D_FIFO
        assign h2d_ready = !h2d_fill[FIFO_ADDR_WIDTH] && (h2d_fill < ((1 << BITS_TO_START_XMIT) + H2D_FIFO_THRESHOLD ));
    `else
        assign h2d_ready = !h2d_fill[FIFO_ADDR_WIDTH] && !(&h2d_fill[FIFO_ADDR_WIDTH-1:3]); // same as with synthesis
    `endif
`else
        assign h2d_ready = !h2d_fill[FIFO_ADDR_WIDTH] && !(&h2d_fill[FIFO_ADDR_WIDTH-1:3]);
`endif

assign ll_d2h_almost_full   = d2h_fill[FIFO_ADDR_WIDTH] || &d2h_fill[FIFO_ADDR_WIDTH-1:6]; // 63 dwords (maybe use :5?) - time to tell device to stop 

//    assign ll_frame_req_w = !ll_frame_busy && h2d_pending && (((h2d_type == H2D_TYPE_FIS_LAST) && h2d_fifo_wr ) || (|h2d_fill[FIFO_ADDR_WIDTH : BITS_TO_START_XMIT]));
@@ -318,6 +346,8 @@ assign debug_phy = debug_phy0;
        // to phy
        .phy_data_out     (ll2ph_data_in),         // output[31:0] wire 
        .phy_isk_out      (ll2ph_charisk_in),      // output[3:0] wire   // charisk
        .debug_is_data    (debug_is_data),         // output reg @clk (sata clk) - last symbol was data output
        .debug_dmatp      (debug_dmatp),           // output reg @clk (sata clk) - received CODE_DMATP
        .debug_out        (debug_link)
    );
    
+103 −7
Original line number Diff line number Diff line
@@ -190,6 +190,8 @@ module ahci_top#(
    

    output             irq, // CPU interrupt request
    input              debug_link_send_data, // @posedge sata_clk - last symbol was data output (to count sent out)
    input              debug_link_dmatp,     // link received DMATp from device
    
`ifdef USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
@@ -1204,6 +1206,7 @@ wire [9:0] xmit_dbg_01;
                .soft_write_addr (soft_write_addr), // input[9:0] 
                .soft_write_data (soft_write_data), // input[31:0] 
                .soft_write_en   (soft_write_en), // input
                .cfis            (fsnd_cfis_xmit), // input command FIS - to reset dword counter
                .h2d_data        (h2d_data), // input[31:0] 
                .h2d_type        (h2d_type), // input[1:0] 
                .h2d_valid       (h2d_valid), // input
@@ -1212,6 +1215,8 @@ wire [9:0] xmit_dbg_01;
                .d2h_type        (d2h_type), // input[1:0] 
                .d2h_valid       (d2h_valid), // input
                .d2h_ready       (d2h_ready), // input
                .debug_link_send_data(debug_link_send_data), // input
                .debug_link_dmatp  (debug_link_dmatp),        // link received DMATp from device
                .datascope_clk   (datascope_clk), // output
                .datascope_waddr (datascope_waddr), // output[9:0] reg 
                .datascope_we    (datascope_we), // output
@@ -1327,6 +1332,8 @@ module datascope_timing #(
    input              [31:0] soft_write_data, 
    input                     soft_write_en,
    
    input                     cfis, // to reset send counter
    
    // outgoing FISes
    input              [31:0] h2d_data,     // 32-bit data from the system memory to HBA (dma data)
    input              [ 1:0] h2d_type,     // 0 - data, 1 - FIS head, 2 - FIS END (make FIS_Last?)
@@ -1341,6 +1348,8 @@ module datascope_timing #(
    input                     d2h_valid,   // Data available from the transport layer in FIFO                
    input                     d2h_ready,   // This module or DMA consumes DWORD
    
    input                     debug_link_send_data, // @posedge mclk (sata_clk, 75MHz)  - last symbol was data output (to count sent out)
    input                     debug_link_dmatp,     // link received DMATp from device
    output                        datascope_clk,
    output reg [ADDRESS_BITS-1:0] datascope_waddr,
    output                        datascope_we,
@@ -1360,6 +1369,9 @@ module datascope_timing #(
    reg                [31:0] fis_data;
    reg                [27:0] cur_time;
    reg                       was_h2d_last;
    reg                       h2d_ready_d; // delayed h2d_ready to count 1->0 transitions
    reg                [ 7:0] h2d_nready_cntr; // count (infrequent) events when h2d FIFO turns off ready 
//    reg                       
    
    wire                      fis_start = (h2d_valid && h2d_ready && (h2d_type == 1)) ||
                                          (d2h_valid && d2h_ready && (d2h_type == 1));
@@ -1367,11 +1379,44 @@ module datascope_timing #(
//    wire                      fis_end_we = (fis_left == 0) || fis_end;

    wire                      pre_we_w =  fis_run && (d2h_valid?(d2h_valid && d2h_ready):(h2d_valid && h2d_ready));
    
    reg                       fis_run_d2;
    reg                       fis_run_d3;
    reg                       fis_run_d4; // to read non 0x39 d2h fis
    reg                       fis_run_d5; // number of dwords sent by link a s data symbols
//  reg                       fis_first;
    reg                       data_fis;
    reg                       pre_we_r;                                      
    reg                       we_r;
    
    wire                      inc_dw_cntr =  fis_run && (d2h_valid?(d2h_ready && (d2h_type == 0)):(h2d_valid && h2d_ready));
    
    wire is_cfis_w = h2d_valid && (h2d_data[ 7: 0] == 8'h27) && // valid @ fis_start
                                 ((h2d_data[23:16] == 8'h25) || // Read DMA Extended
                                  (h2d_data[23:16] == 8'h35) || // Write DMA Extended
                                  (h2d_data[23:16] == 8'hC8) || // Read DMA
                                  (h2d_data[23:16] == 8'hCA));   // Write DMA
    reg  is_cfis_r;                                               
    reg                [23:0] last_dma_cmd;
    reg                       set_dma_count;                                      
    reg                [21:0] dw_count;
    wire                [7:0] fis_data_w = d2h_valid ? d2h_data[7:0] : h2d_data[7:0]; 
    reg                [31:0] non_dma_act; // last D2H FIS that was not DMA activate, received after DMA/IO command
    reg                       set_non_dma_act;
    reg                [21:0] link_count;
    reg                [21:0] link_count_latched;
    
    reg                       reset_link_count; // data FIS from dma command until
    reg                       was_link_dmatp;   //
    
//    input              debug_link_dmatp,      // link received DMATp from device
    
    
    assign datascope_we =  we_r;
    assign datascope_clk = clk;
    
    
    
    always @ (posedge clk) begin
        was_h2d_last <= h2d_type[1] && h2d_valid && h2d_ready;
    
@@ -1387,14 +1432,26 @@ module datascope_timing #(
        if (write_punch_time || fis_start)   datascope_di <= {write_punch_time?{1'b1,punch_tag}:{3'b0,d2h_valid},cur_time};
        else if (fis_we)                     datascope_di <= fis_data;
        else if (!fis_run    && fis_run_d)   datascope_di <= {19'h7fff8, fis_len};
        else if (!fis_run_d  && fis_run_d2)  datascope_di <= {10'h2a8,   dw_count};
        else if (!fis_run_d2 && fis_run_d3)  datascope_di <= {8'h55,   last_dma_cmd};
        else if (!fis_run_d3 && fis_run_d4)  datascope_di <= non_dma_act;
        else if (!fis_run_d4 && fis_run_d5)  datascope_di <= {h2d_nready_cntr[7:0], was_link_dmatp, 1'b0, link_count_latched};

        pre_we_r <= pre_we_w || fis_start ;
    
        we_r <= write_punch_time || fis_start || (fis_we ? pre_we_r : (!fis_run && fis_run_d));
//        we_r <= write_punch_time || fis_start || (fis_we ? pre_we_r : (!fis_run && fis_run_d));
        we_r <= write_punch_time || fis_start || (fis_we ? pre_we_r : (!fis_run && (fis_run_d || fis_run_d2 || fis_run_d3 || fis_run_d4  || fis_run_d5))); // 3 after
        
        if     (fis_start) fis_left <= FIS_LEN - 1;
        else if (pre_we_w) fis_left <= fis_left - 1;
        
//        if     (fis_start) fis_first <= 1;
//       else if (pre_we_w) fis_first <= 0;

        if      (fis_end)               data_fis <= 0;
//        else if (pre_we_w && fis_start) data_fis <= fis_data_w == 8'h46;
        else if (fis_start) data_fis <= fis_data_w == 8'h46;
        
        if      (rst)                        fis_we <= 0;
        else if (fis_start)                  fis_we <= 1;
        else if ((fis_left == 0) || fis_end) fis_we <= 0;
@@ -1404,6 +1461,45 @@ module datascope_timing #(
        else if (fis_end)    fis_run <= 0;

        fis_run_d <=  fis_run;
        fis_run_d2 <= fis_run_d;
        fis_run_d3 <= fis_run_d2;
        fis_run_d4 <= fis_run_d3; 
        fis_run_d5 <= fis_run_d4;
               
        if      (cfis)                    dw_count <= 0;
        else if (inc_dw_cntr && data_fis) dw_count <= dw_count + 1;
        
        if      (rst)                                reset_link_count <= 0;
        else if (cfis)                               reset_link_count <= 1;
        else if (fis_start && (fis_data_w == 8'h46)) reset_link_count <= 0;

        if      (reset_link_count)     link_count <= 0;
        else if (debug_link_send_data) link_count <= link_count + 1; // will only be valid later, latch at next fis start
        
        if (fis_start) link_count_latched <= link_count;
        
        
        if      (reset_link_count)     was_link_dmatp <= 0;
        else if (debug_link_dmatp)     was_link_dmatp <= 1;
        
        h2d_ready_d <= h2d_ready;
        
        if      (rst)                       h2d_nready_cntr <= 0;
        else if (!h2d_ready && h2d_ready_d) h2d_nready_cntr <= h2d_nready_cntr+1;
        
        
        if (fis_start) is_cfis_r <= is_cfis_w;
        
        if (fis_start && is_cfis_w) last_dma_cmd[23:16] <= h2d_data[23:16]; // command code
        
        set_dma_count <=  (fis_len == 3) && h2d_valid && h2d_ready && is_cfis_r;
        
        if (set_dma_count) last_dma_cmd[15:0] <= fis_data[15:0];
        
        set_non_dma_act <= fis_start && d2h_valid && (fis_data_w != 8'h39);
        
        if      (set_dma_count)   non_dma_act <= 32'h33333333;
        else if (set_non_dma_act) non_dma_act <= fis_data;
        
        if     (fis_start) fis_len <= d2h_valid? 0 : 1;
        else if (pre_we_w) fis_len <= fis_len + 1;
+8 −1
Original line number Diff line number Diff line
@@ -239,6 +239,8 @@
    
    reg          [2:0] nhrst_r;
    wire               hrst = !nhrst_r[2];
    wire               debug_link_send_data; // @sata clk - last symbol was data output
    wire               debug_link_dmatp;     // @clk (sata clk) - received CODE_DMATP
    
    wire [FREQ_METER_WIDTH-1:0] xclk_period;
`ifdef USE_DATASCOPE
@@ -403,7 +405,8 @@
        .sctl_ipm          (sctl_ipm),          // output[3:0] 
        .sctl_spd          (sctl_spd),          // output[3:0] 
        .irq               (irq),               // output

        .debug_link_send_data (debug_link_send_data), // input @posedge sata_clk - last symbol was data output (to count sent out)
        .debug_link_dmatp  (debug_link_dmatp),        // link received DMATp from device
`ifdef USE_DATASCOPE
        .datascope1_clk    (datascope_clk),     // input
        .datascope1_waddr  (datascope_waddr),   // input[9:0] 
@@ -489,6 +492,10 @@
        .txn_out           (TXN),               // output wire 
        .rxp_in            (RXP),               // input wire 
        .rxn_in            (RXN),               // input wire
        .debug_is_data     (debug_link_send_data), //output  @clk (sata clk) - last symbol was data output
        .debug_dmatp       (debug_link_dmatp),  // @clk (sata clk) - received CODE_DMATP
        
        
`ifdef USE_DATASCOPE
        .datascope_clk     (datascope_clk),     // output
        .datascope_waddr   (datascope_waddr),   // output[9:0] 
+6 −1
Original line number Diff line number Diff line
@@ -47,7 +47,8 @@ module sata_device(
//    reg  [31:0] DEV_DATA;
    integer DEV_DATA;
//`endif

//`define TERMINATE_DMA_H2D
//`undef TERMINATE_DMA_H2D
wire            phy_ready;

wire    [31:0]  phy2dev_data;
@@ -569,6 +570,10 @@ task linkMonitorFIS;
                    cnt = cnt + 1;
                    if (cnt <= 2048)
                        pause = pause + receive_data_pause[cnt];
`ifdef TERMINATE_DMA_H2D
        linkSendPrim("DMAT");
`endif
                        
                end    
            end
            @ (posedge clk)
+10 −0
Original line number Diff line number Diff line
@@ -99,6 +99,8 @@ module link #(
    // to phy
    output  wire    [DATA_BYTE_WIDTH*8 - 1:0] phy_data_out,
    output  wire    [DATA_BYTE_WIDTH   - 1:0] phy_isk_out,   // charisk
    output reg                                debug_is_data, // @clk (sata clk) - last symbol was data output
    output reg                                debug_dmatp,  // @clk (sata clk) - received CODE_DMATP
    // debug
    output                             [31:0] debug_out      //
);
@@ -580,6 +582,10 @@ begin
end
endgenerate

always @ (posedge clk) begin
     debug_dmatp <= rcvd_dword[CODE_DMATP];
end

// select which primitive shall be sent 
wire    [PRIM_NUM - 1:0]    select_prim;
assign  select_prim[CODE_SYNCP]     = ~alignes_pair & (state_idle | state_sync_esc | state_rcvr_wait | state_reset);
@@ -618,6 +624,10 @@ always @ (posedge clk)
                    {DATA_BYTE_WIDTH*8{select_prim[CODE_CRC]}}    & prim_data[CODE_CRC]    |
                    {DATA_BYTE_WIDTH*8{select_prim[CODE_DATA]}}   & prim_data[CODE_DATA];

always @ (posedge clk)
    debug_is_data <=  select_prim[CODE_DATA];


always @ (posedge clk)
    to_phy_isk <= rst | ~select_prim[CODE_DATA] & ~select_prim[CODE_CRC] ? {{(DATA_BYTE_WIDTH - 1){1'b0}}, 1'b1} : {DATA_BYTE_WIDTH{1'b0}} ;

Loading