Commit 3e682017 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

working on the afi multiplexer to trasfer up tp 4 compressor output data to the system memory

parent 0b0f5092
Loading
Loading
Loading
Loading

axi/cmprs_afi_mux.v

0 → 100644
+323 −0
Original line number Diff line number Diff line
/*******************************************************************************
 * Module: cmprs_afi_mux
 * Date:2015-06-26  
 * Author: andrey     
 * Description: Writes comressor data from up to 4 channels to system memory over AXI_HP
 *
 * Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
 * cmprs_afi_mux.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  cmprs_afi_mux.v is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
 *******************************************************************************/
`timescale 1ns/1ps

module  cmprs_afi_mux#(
    parameter AFI_MUX_BUF_LATENCY = 2  // buffers read latency from fifo_ren* to fifo_rdata* valid : 2 if no register layers are used
)(
    input                         rst,
    input                         mclk, // for command/status
    input                         hclk,   // global clock to run axi_hp @ 150MHz, shared by all compressor channels
    // programming interface
    input                   [7:0] cmd_ad,      // byte-serial command address/data (up to 6 bytes: AL-AH-D0-D1-D2-D3 
    input                         cmd_stb,     // strobe (with first byte) for the command a/d
    output                  [7:0] status_ad,   // status address/data - up to 5 bytes: A - {seq,status[1:0]} - status[2:9] - status[10:17] - status[18:25]
    output                        status_rq,   // input request to send status downstream
    input                         status_start, // Acknowledge of the first status packet byte (address)
    
    // compressor channel 0
    output                        fifo_rst0,      // reset FIFO (set read adderss to write, reset count)
    output                        fifo_ren0,
    input                  [63:0] fifo_rdata0,
//    input                         fifo_eof0,        // single rclk pulse signalling EOF
    output                        eof_written0,   // confirm frame written ofer AFI to the system memory (single rclk pulse)
    input                         fifo_flush0,    // EOF, need to output all what is in FIFO (Stays active until enough data chunks are read)
    input                  [7:0]  fifo_count0,     // number of 32-byte chunks in FIFO

    // compressor channel 1
    output                        fifo_rst1,      // reset FIFO (set read adderss to write, reset count)
    output                        fifo_ren1,
    input                  [63:0] fifo_rdata1,
//    input                         fifo_eof1,        // single rclk pulse signalling EOF
    output                        eof_written1,   // confirm frame written ofer AFI to the system memory (single rclk pulse)
    input                         fifo_flush1,    // EOF, need to output all what is in FIFO (Stays active until enough data chunks are read)
    input                  [7:0]  fifo_count1,     // number of 32-byte chunks in FIFO

    // compressor channel 2
    output                        fifo_rst2,      // reset FIFO (set read adderss to write, reset count)
    output                        fifo_ren2,
    input                  [63:0] fifo_rdata2,
//    input                         fifo_eof2,        // single rclk pulse signalling EOF
    output                        eof_written2,   // confirm frame written ofer AFI to the system memory (single rclk pulse)
    input                         fifo_flush2,    // EOF, need to output all what is in FIFO (Stays active until enough data chunks are read)
    input                  [7:0]  fifo_count2,     // number of 32-byte chunks in FIFO

    // compressor channel 3
    output                        fifo_rst3,      // reset FIFO (set read adderss to write, reset count)
    output                        fifo_ren3,
    input                  [63:0] fifo_rdata3,
//    input                         fifo_eof3,        // single rclk pulse signalling EOF
    output                        eof_written3,   // confirm frame written ofer AFI to the system memory (single rclk pulse)
    input                         fifo_flush3,    // EOF, need to output all what is in FIFO (Stays active until enough data chunks are read)
    input                  [7:0]  fifo_count3,     // number of 32-byte chunks in FIFO
    
    // axi_hp signals write channel
    // write address
    output                 [31:0] afi_awaddr,
    output                        afi_awvalid,
    input                         afi_awready, // @SuppressThisWarning VEditor unused - used FIF0 level
    output                 [ 5:0] afi_awid,
    output                 [ 1:0] afi_awlock,
    output                 [ 3:0] afi_awcache,
    output                 [ 2:0] afi_awprot,
    output                 [ 3:0] afi_awlen,
    output                 [ 2:0] afi_awsize,
    output                 [ 1:0] afi_awburst,
    output                 [ 3:0] afi_awqos,
    // write data
    output                 [63:0] afi_wdata,
    output                        afi_wvalid,
    input                         afi_wready,  // @SuppressThisWarning VEditor unused - used FIF0 level
    output                 [ 5:0] afi_wid,
    output                        afi_wlast,
    output                 [ 7:0] afi_wstrb,
    // write response
    input                         afi_bvalid,
    output                        afi_bready,
    input                  [ 5:0] afi_bid,
    input                  [ 1:0] afi_bresp,    // @SuppressThisWarning VEditor unused
    // PL extra (non-AXI) signals
    input                  [ 7:0] afi_wcount,
    input                  [ 5:0] afi_wacount,
    output                        afi_wrissuecap1en
);
    reg         en;      // enable mux
    reg   [3:0] en_chn;  // per-channel enable 
//    reg   [2:0] cur_chn;          // 'b0xx - none, 'b1** - ** - channel number (should match fifo_ren*)
    reg   [1:0] cur_chn;           // 'b0xx - none, 'b1** - ** - channel number (should match fifo_ren*)
    reg   [7:0] left_to_eof[0:3];  // number of chunks left to end of frame
    reg   [3:0] fifo_flush_d;      // fifo_flush* delayed by 1 clk (to detect rising edge
    reg   [3:0] eof_stb;           // single-cycle pulse after fifo_flush is asserted
//    reg   [1:0] w64_cnt;           // count 64-bit words in a chunk
    reg   [8:0] counts_corr0[0:3]; // registers to hold corrected (decremented currently processed ones if any) fifo count values, MSB - needs flush
    reg   [8:0] counts_corr1[0:1]; // first arbitration level winning values
    reg   [8:0] counts_corr2;      // second arbitration level winning values
    
    reg   [1:0] winner1;           // 2 first level arbitration winners
    reg   [1:0] winner2;           // 2-bit second level arbitration winner
    
//    reg   [1:0] cur_chn;          // Can it be the same as cur_chn?
    wire  [7:0] fifo_count0_m1 = fifo_count0 - 1;
    wire  [7:0] fifo_count1_m1 = fifo_count1 - 1;
    wire  [7:0] fifo_count2_m1 = fifo_count2 - 1;
    wire  [7:0] fifo_count3_m1 = fifo_count3 - 1;
    // See if we need to bother - any channel needs flushing or has >= 4 of 32-byte chunks to transfer in a single AXI 16-burst 64 bit wide (latency = 4)
    wire        need_to_bother = |counts_corr2[8:2];
    reg         ready_to_start; // TBD: either idle or soon will finish the previous burst (include AFI FIFO level here too?)
    wire  [3:0] last_chunk_w;
    reg   [2:0] busy; // TODO: adjust number of bits. During continuous run busy is deasseted for 1 clock cycle
    wire        done_burst_w; // de-asset busy
    wire        pre_busy_w;
    reg         last_burst_in_frame;
//    reg   [1:0] wlen32; // 2 high bits of burst len (LSB are always 2'b11)
    
    reg   [3:0] wleft; // number of 64-bit words left to be sent - also used as awlen (valid @ awvalid)
    
    reg  [26:0] chunk_addr_chn[0:3]; //system memory address in "chunks" (32-bytes)
    reg  [26:0] chunk_addr;
    reg         awvalid;
    reg         wvalid;
    reg         wlast;
    reg   [3:0] eof_written;
    reg  [63:0] wdata;     // registered data from one of the 4 buffers
    wire        wdata_en;  // register enable for wdata
    wire  [1:0] wdata_sel; // source select for wdata
    reg   [3:0] fifo_ren;
    // use last_chunk_w to apply a special id to waddr and wdata and watch for it during readout
    // compose ID of channel number, frame bumber LSBs and last/not last chunk
//    assign last_chunk_w[3:0] = {~(|left_to_eof[3]),~(|left_to_eof[2]),~(|left_to_eof[1]),~(|left_to_eof[0])};
    assign last_chunk_w[3:0] = {(left_to_eof[3]==1)?1'b1:1'b0,
                                (left_to_eof[2]==1)?1'b1:1'b0,
                                (left_to_eof[1]==1)?1'b1:1'b0,
                                (left_to_eof[0]==1)?1'b1:1'b0};
    
    assign pre_busy_w = !busy && ready_to_start && need_to_bother;
    assign done_burst_w = busy && !(|wleft[3:1]);  // when wleft[3:0] == 0, busy is 0
    assign eof_written0 = eof_written[0];
    assign eof_written1 = eof_written[1];
    assign eof_written2 = eof_written[2];
    assign eof_written3 = eof_written[3];
    assign fifo_ren0 = fifo_ren[0];
    assign fifo_ren1 = fifo_ren[1];
    assign fifo_ren2 = fifo_ren[2];
    assign fifo_ren3 = fifo_ren[3];
    
    assign afi_awaddr =  {chunk_addr,5'b0};
    assign afi_awid =    {3'b0,last_burst_in_frame,cur_chn}; 
    assign afi_awvalid = awvalid;
    assign afi_awlen = wleft;
//    assign afi_wid = {3'b0,last_burst_in_frame,cur_chn};
//    assign afi_wvalid = wvalid;
//    assign afi_wlast = wlast;
    assign afi_wdata = wdata;
    assign afi_bready = 1'b1; // always ready
    
// other fixed-value AFI signals
    assign afi_awlock =        2'h0;
    assign afi_awcache =       4'h3;
    assign afi_awprot =        3'h0;
    assign afi_awsize =        3'h3;
    assign afi_awburst =       2'h1;
    assign afi_awqos =         4'h0;
    assign afi_wstrb =         8'hff;
    assign afi_wrissuecap1en = 1'b0;
    
    
    
    always @ (posedge hclk) begin
        ready_to_start <= en && // ready to strta a burst
                          !afi_wacount[5] && !(&afi_wacount[4:1]) &&  // >=2 free 
                          !afi_wcount[7] &&  !(&afi_wcount[6:3]);     // >=8 free (4 would be enough too)
    
        fifo_flush_d <= {fifo_flush3,fifo_flush2,fifo_flush1,fifo_flush0};
        eof_stb <= {fifo_flush3 & ~fifo_flush_d[3],
                    fifo_flush2 & ~fifo_flush_d[2],
                    fifo_flush1 & ~fifo_flush_d[1],
                    fifo_flush0 & ~fifo_flush_d[0]};
                    
        // TODO: change &w64_cnt[1:0] so left_to_eof[*] will be updated earlier and valid at pre_busy_w       
        // Done, updating at the first (not last) word of 4
        if (eof_stb[0])                      left_to_eof[0] <= fifo_count0 - (fifo_ren0 & (&wleft[1:0]));
        else if (fifo_ren0 & (&wleft[1:0]))  left_to_eof[0] <= left_to_eof[0] - 1;
    
        if (eof_stb[1])                      left_to_eof[1] <= fifo_count1 - (fifo_ren1 & (&wleft[1:0]));
        else if (fifo_ren1 & (&wleft[1:0]))  left_to_eof[1] <= left_to_eof[1] - 1;
    
        if (eof_stb[2])                      left_to_eof[2] <= fifo_count2 - (fifo_ren2 & (&wleft[1:0]));
        else if (fifo_ren2 & (&wleft[1:0]))  left_to_eof[2] <= left_to_eof[2] - 1;
    
        if (eof_stb[3])                      left_to_eof[3] <= fifo_count3 - (fifo_ren3 & (&wleft[1:0]));
        else if (fifo_ren3 & (&wleft[1:0]))  left_to_eof[3] <= left_to_eof[3] - 1;
    
        // Calculate corrected values decrementing currently served channel (if any) values by 1 (latency 1 clk)
        
        if      ((fifo_count0 == 0) || !en_chn[0]) counts_corr0[0] <= 0;
        else if (fifo_ren[0])                      counts_corr0[0] <= (fifo_count0_m1 == 0)? 0 : {fifo_flush0,fifo_count0_m1};
        else                                       counts_corr0[0] <= {fifo_flush0,fifo_count0};

        if      ((fifo_count1 == 0) || !en_chn[1]) counts_corr0[1] <= 0;
        else if (fifo_ren[1])                      counts_corr0[1] <= (fifo_count1_m1 == 0)? 0 : {fifo_flush1,fifo_count1_m1};
        else                                       counts_corr0[1] <= {fifo_flush1,fifo_count1};

        if      ((fifo_count2 == 0) || !en_chn[2]) counts_corr0[2] <= 0;
        else if (fifo_ren[2])                      counts_corr0[2] <= (fifo_count2_m1 == 0)? 0 : {fifo_flush2,fifo_count2_m1};
        else                                       counts_corr0[2] <= {fifo_flush2,fifo_count2};

        if      ((fifo_count3 == 0) || !en_chn[3]) counts_corr0[3] <= 0;
        else if (fifo_ren[3])                      counts_corr0[3] <= (fifo_count3_m1 == 0)? 0 : {fifo_flush3,fifo_count3_m1};
        else                                       counts_corr0[3] <= {fifo_flush3,fifo_count3};

        // 2-level arbitration
        // first arbitration level (latency 2 clk)
        if (counts_corr0[1] > counts_corr0[0]) begin
            counts_corr1[0] <= counts_corr0[1];
            winner1[0] <=      1;
        end else begin
            counts_corr1[0] <= counts_corr0[0];
            winner1[0] <=      0;
        end

        if (counts_corr0[3] > counts_corr0[2]) begin
            counts_corr1[1] <= counts_corr0[3];
            winner1[1] <=      1;
        end else begin
            counts_corr1[1] <= counts_corr0[2];
            winner1[1] <=      0;
        end
        
        // second arbitration level (latency 3 clk)
        if (counts_corr1[1] > counts_corr1[0]) begin
            counts_corr2 <= counts_corr1[1];
            winner2 <=      {1'b1,winner1[1]};
        end else begin
            counts_corr2 <= counts_corr1[0];
            winner2 <=      {1'b0,winner1[0]};
        end
        //ready_to_start need_to_bother
        //done_burst
        if      (!en)          busy <= 0;
        else if (pre_busy_w)   busy <= {busy[1:0],1'b1};
        else if (done_burst_w) busy <= {busy[1:0],1'b0};
        
        if      (!en)        wleft <= 0;
        else if (pre_busy_w) wleft <= {(|counts_corr2[7:2])? 2'b11 : left_to_eof[winner2][1:0], 2'b11};
        else if (wleft != 0) wleft <= wleft - 1;

        if      (!en)        wvalid <= 0;
        else if (pre_busy_w) wvalid <= 1;
        else if (wlast)      wvalid <= 0; // should be after pre_busy_w as both can happen simultaneously

//fifo_ren
        if      (!en)          fifo_ren <= 0;
        else if (pre_busy_w)   fifo_ren <= {(winner2 == 3) ?1'b1:1'b0,
                                            (winner2 == 2) ?1'b1:1'b0,
                                            (winner2 == 1) ?1'b1:1'b0,
                                            (winner2 == 0) ?1'b1:1'b0};
        else if (wlast)        fifo_ren <= 0;
        
        awvalid <= pre_busy_w; // no need to wait for afi_awready, will use fifo levels to enable pre_busy_w
        if (pre_busy_w)  begin
            cur_chn <= winner2;
            last_burst_in_frame <= last_chunk_w[winner2];
            wleft <= {(|counts_corr2[7:2])? 2'b11 : left_to_eof[winner2][1:0], 2'b11};
            chunk_addr <= chunk_addr_chn[winner2];
                
        end
        
        wlast <= done_burst_w; // when wleft==4'h1
        // wdata register mux
        if (wdata_en) wdata <= wdata_sel[1]?(wdata_sel[1]?fifo_rdata3:fifo_rdata2):(wdata_sel[1]?fifo_rdata1:fifo_rdata0);
        
        // Watch write responce channel, detect EOF IDs, generate eof_written* output signals
        eof_written[0] <=  afi_bvalid && (afi_bid[2:0]== 3'h4);
        eof_written[1] <=  afi_bvalid && (afi_bid[2:0]== 3'h5);
        eof_written[2] <=  afi_bvalid && (afi_bid[2:0]== 3'h6);
        eof_written[3] <=  afi_bvalid && (afi_bid[2:0]== 3'h7);
        
        // calculate and rollover channel addresses
        
        
    end

    // delay write channel controls signal to match data latency. wid bits will be optimized (6 -> 3)    
    dly_16 #(
        .WIDTH(8)
    ) afi_wx_i (
        .clk       (hclk), // input
        .rst       (!en),  // input
        .dly       (AFI_MUX_BUF_LATENCY), // input[3:0] will delay by AFI_MUX_BUF_LATENCY+1 (normally 3) 
        .din       ({    wvalid,     wlast, 3'b0,last_burst_in_frame, cur_chn}), // input[0:0] 
        .dout      ({afi_wvalid, afi_wlast, afi_wid}) // output[0:0] 
    );

    dly_16 #(
        .WIDTH(3)
    ) afi_wdata_i (
        .clk       (hclk), // input
        .rst       (!en),  // input
        .dly       (AFI_MUX_BUF_LATENCY-1), // input[3:0] will delay by AFI_MUX_BUF_LATENCY+1 (normally 3) 
        .din       ({wvalid, cur_chn}), // input[0:0] 
        .dout      ({wdata_en,wdata_sel}) // output[0:0] 
    );


endmodule