/******************************************************************************* * Module: cmprs_afi_mux_ptr_wresp * Date:2015-06-28 * Author: Andrey Filippov * Description: Maintain 4-channel chunk pointers for wrirte response * Advance 32-byte chunk pointers for each AXI burst and each frame (4*2=8 pointers) * * Copyright (c) 2015 Elphel, Inc. * cmprs_afi_mux_ptr_wresp.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_ptr_wresp.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 . *******************************************************************************/ `timescale 1ns/1ps module cmprs_afi_mux_ptr_wresp( input hclk, // global clock to run axi_hp @ 150MHz, shared by all compressor channels // Write dual port 4x27 channel length RAM (shadows 1/2 of the similar RAM for main pointers) input [26:0] length_di, // data to write per-channle buffer length in chunks input [ 1:0] length_wa, // channel address to write lengths input length_we, // write enable length data input en, // 0 - resets, 0->1 resets all pointers. While reset allows write response input [ 3:0] reset_pointers, // per-channel - reset pointers input [ 2:0] chunk_ptr_ra, // chunk pointer read address {eof, chn[1:0]} output [26:0] chunk_ptr_rd, // chunk pointer read data (non-registered output reg [ 3:0] eof_written, // per-channel end of frame confirmed written to system memory by write response // AFI write response channels input afi_bvalid, output afi_bready, input [ 5:0] afi_bid // encodes channel, eof, and burst size minus 1 in chunks (0..3) ); reg [3:0] reset_rq; // request to reset pointers when ready reg [3:0] reset_rq_pri; // one-hot reset rq wire [1:0] reset_rq_enc; // encoded reset_rq_pri wire start_resetting_w; reg [1:0] resetting; // resetting chunk_pointer and eof_pointer wire [2:0] ptr_wa; // pointer memory write port address, msb - eof/current, 2 LSB - channel reg ptr_we; // pointer memory write enable reg [26:0] ptr_ram[0:7]; // pointer (current and eof) memory (in 32-byte chunks wire [26:0] ptr_ram_di; // data to be written to ptr_ram reg [26:0] len_ram[0:3]; // start chunk/num cunks in a buffer (write port @mclk) reg [26:0] chunk_ptr_inc; // incremented by 1..4 chunk pointer reg [27:0] chunk_ptr_rovr; // incremented chunk pointer, decremented by length (MSB - sign) reg [ 3:0] busy; // one-hot busy stages (usually end with [3] // reg [ 5:0] id_r; // registered ID data reg [ 4:0] id_r; // registered ID data - MSB is unused reg [1:0] chn; // selected channel reg eof; // eof register being written reg last_burst_in_frame; // this response is for eof reg [2:0] chunk_inc; reg afi_bready_r; // reg afi_bvalid_r; // make it slow; wire pre_busy; wire pre_we; reg en_d; //enable delayed by 1 cycle assign reset_rq_enc = {reset_rq_pri[3] | reset_rq_pri[2], reset_rq_pri[3] | reset_rq_pri[1]}; assign ptr_ram_di= resetting[1] ? 27'b0 : (chunk_ptr_rovr[27] ? chunk_ptr_inc : chunk_ptr_rovr[26:0]); assign ptr_wa = {eof,chn}; assign afi_bready = afi_bready_r; assign pre_we= resetting[0] || // a pair of cycles to reset chunk pointer and frame chunk pointer busy[2] || // always update chunk pointer (busy[3] && last_burst_in_frame); // optionally update frame chunk pointer (same value) assign pre_busy= afi_bvalid_r && en && !(|busy[1:0]) && !pre_we; assign start_resetting_w = !afi_bvalid_r && en && !(|busy[1:0]) && !pre_we && (|reset_rq); assign chunk_ptr_rd = ptr_ram[chunk_ptr_ra]; always @ (posedge hclk) begin en_d <= en; // write length RAM if (length_we) len_ram[length_wa] <= length_di; afi_bvalid_r <= afi_bvalid; afi_bready_r <= !en || pre_busy; // (!busy[0] && !pre_busy && !resetting[0] && !start_resetting_w); busy <= {busy[2:0], pre_busy}; // adjust bits // id_r <= afi_bid; id_r <= afi_bid[4:0]; // id_r[5] is never used - revoved if (start_resetting_w) reset_rq_pri <= {reset_rq[3] & ~(|reset_rq[2:0]), reset_rq[2] & ~(|reset_rq[1:0]), reset_rq[1] & ~reset_rq[0], reset_rq[0]}; if (en && !en_d) reset_rq <= 4'hf; // request reset all else reset_rq <= reset_pointers | (reset_rq & ~({4{resetting[0] &~ resetting[1]}} & reset_rq_pri)); if (!en) resetting <= 0; else resetting <= {resetting[0], start_resetting_w | (resetting[0] & ~resetting[1])}; if (resetting == 2'b01) chn <= reset_rq_enc; else if (busy[0]) chn <= id_r[0 +: 2]; if (busy[0]) begin // first busy cycle last_burst_in_frame <= id_r[2]; chunk_inc <= {1'b0,id_r[3 +:2]} + 1; end ptr_we <= pre_we; if ((resetting == 2'b01) || busy[0]) eof <= 0; else if (ptr_we) eof <= 1; // always second write cycle if (busy[1]) chunk_ptr_inc <= ptr_ram[ptr_wa] + chunk_inc; // second clock of busy if (busy[2]) chunk_ptr_rovr <={1'b0,chunk_ptr_inc} - {1'b0,len_ram[chn]}; // third clock of busy // write to ptr_ram (1 or 2 locations - if eof) if (ptr_we) ptr_ram[ptr_wa] <= ptr_ram_di; // Watch write response channel, detect EOF IDs, generate eof_written* output signals eof_written[0] <= afi_bvalid_r && afi_bready_r && (id_r[2:0]== 3'h4); eof_written[1] <= afi_bvalid_r && afi_bready_r && (id_r[2:0]== 3'h5); eof_written[2] <= afi_bvalid_r && afi_bready_r && (id_r[2:0]== 3'h6); eof_written[3] <= afi_bvalid_r && afi_bready_r && (id_r[2:0]== 3'h7); end endmodule