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 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