module axi_mpeg2encoder_wrapper #( parameter AXI_IDWIDTH = 4 ) ( input wire rstn, input wire clk, // AXI-MM AW interface ---------------------------------------------------- output wire s_axi_awready, input wire s_axi_awvalid, input wire [ 63:0] s_axi_awaddr, input wire [ 7:0] s_axi_awlen, input wire [AXI_IDWIDTH-1:0] s_axi_awid, // AXI-MM W interface ---------------------------------------------------- output wire s_axi_wready, input wire s_axi_wvalid, input wire s_axi_wlast, input wire [ 63:0] s_axi_wdata, // AXI-MM B interface ---------------------------------------------------- input wire s_axi_bready, output wire s_axi_bvalid, output wire [AXI_IDWIDTH-1:0] s_axi_bid, output wire [ 1:0] s_axi_bresp, // AXI-MM AR interface ---------------------------------------------------- output wire s_axi_arready, input wire s_axi_arvalid, input wire [ 63:0] s_axi_araddr, input wire [ 7:0] s_axi_arlen, input wire [AXI_IDWIDTH-1:0] s_axi_arid, // AXI-MM R interface ---------------------------------------------------- input wire s_axi_rready, output wire s_axi_rvalid, output wire s_axi_rlast, output reg [ 63:0] s_axi_rdata, output wire [AXI_IDWIDTH-1:0] s_axi_rid, output wire [ 1:0] s_axi_rresp ); // --------------------------------------------------------------------------------------- // AXI READ state machine // --------------------------------------------------------------------------------------- enum reg [0:0] {R_IDLE, R_BUSY} rstate = R_IDLE; reg [AXI_IDWIDTH-1:0] rid = '0; reg [ 7:0] rcount = '0; reg [ 63-3:0] raddr_63_3, raddr_63_3_r; wire [ 63:0] raddr = {raddr_63_3 , 3'h0}; wire [ 63:0] raddr_r = {raddr_63_3_r, 3'h0}; assign s_axi_arready = (rstate == R_IDLE); assign s_axi_rvalid = (rstate == R_BUSY); assign s_axi_rlast = (rstate == R_BUSY) && (rcount == 8'd0); assign s_axi_rid = rid; assign s_axi_rresp = '0; always @ (posedge clk or negedge rstn) if (~rstn) begin rstate <= R_IDLE; rid <= '0; rcount <= '0; end else begin case (rstate) R_IDLE : if (s_axi_arvalid) begin rstate <= R_BUSY; rid <= s_axi_arid; rcount <= s_axi_arlen; end R_BUSY : if (s_axi_rready) begin if (rcount == 8'd0) // the last data of read session rstate <= R_IDLE; rcount <= rcount - 8'd1; end endcase end always_comb if (rstate == R_IDLE && s_axi_arvalid) raddr_63_3 = s_axi_araddr[63:3]; else if (rstate == R_BUSY && s_axi_rready) raddr_63_3 = raddr_63_3_r + 61'h1; else raddr_63_3 = raddr_63_3_r; always @ (posedge clk) raddr_63_3_r <= raddr_63_3; // --------------------------------------------------------------------------------------- // AXI WRITE state machine // --------------------------------------------------------------------------------------- enum reg [1:0] {W_IDLE, W_BUSY, W_RESP} wstate = W_IDLE; reg [AXI_IDWIDTH-1:0] wid = '0; reg [ 7:0] wcount = '0; reg [ 63-3:0] waddr_63_3 = '0; wire [ 63:0] waddr = {waddr_63_3, 3'h0}; assign s_axi_awready = (wstate == W_IDLE); assign s_axi_wready = (wstate == W_BUSY); assign s_axi_bvalid = (wstate == W_RESP); assign s_axi_bid = wid; assign s_axi_bresp = '0; always @ (posedge clk or negedge rstn) if (~rstn) begin wstate <= W_IDLE; wid <= '0; wcount <= '0; waddr_63_3 <= '0; end else begin case (wstate) W_IDLE : if (s_axi_awvalid) begin wstate <= W_BUSY; wid <= s_axi_awid; wcount <= s_axi_awlen; waddr_63_3 <= s_axi_awaddr[63:3]; end W_BUSY : if (s_axi_wvalid) begin if (wcount == 8'd0 || s_axi_wlast) wstate <= W_RESP; wcount <= wcount - 8'd1; waddr_63_3 <= waddr_63_3 + 61'h1; end W_RESP : if (s_axi_bready) wstate <= W_IDLE; default : wstate <= W_IDLE; endcase end function automatic logic [255:0] big_endian_to_little_endian_32B (input logic [255:0] din); logic [255:0] dout; for (int i=0; i<32; i++) dout[i*8 +: 8] = din[(31-i)*8 +: 8]; return dout; endfunction ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // signals of the MPEG2 encoder ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// reg mpeg2_rstn = '0; wire mpeg2_sequence_busy; reg mpeg2_sequence_stop = '0; reg [ 6:0] mpeg2_xsize16 = '0; reg [ 6:0] mpeg2_ysize16 = '0; reg mpeg2_i_en = '0; reg [ 7:0] mpeg2_i_Y0, mpeg2_i_Y1, mpeg2_i_Y2, mpeg2_i_Y3; reg [ 7:0] mpeg2_i_U0, mpeg2_i_U2 ; reg [ 7:0] mpeg2_i_V0, mpeg2_i_V2 ; wire mpeg2_o_en; wire mpeg2_o_last; wire [255:0] mpeg2_o_data; reg [ 15:0] mpeg2_o_addr = '0; reg mpeg2_o_over = '0; // 1: overflow ! reg [255:0] out_buf ['h10000]; // out buffer : a block RAM to save the MPEG2 IP's out data, 32B * 0x10000 = 2 MB reg [255:0] out_buf_rdata; always @ (posedge clk) out_buf_rdata <= out_buf[ (16)'(raddr>>5) ]; // read BRAM always @ (posedge clk) if ( mpeg2_o_en & ~mpeg2_o_over ) out_buf[mpeg2_o_addr] <= big_endian_to_little_endian_32B(mpeg2_o_data); always_comb if ( raddr_r == 64'h00000000 ) // address = 0x00000000 : read status register (reset status and sequence status) s_axi_rdata = {61'h0, mpeg2_sequence_busy, 1'b0, mpeg2_rstn}; else if ( raddr_r == 64'h00000008 ) // address = 0x00000008 : read status register (video frame size) s_axi_rdata = {25'h0, mpeg2_ysize16, 25'h0, mpeg2_xsize16 }; else if ( raddr_r == 64'h00000010 ) // address = 0x00000010 : read status register (out buffer status) s_axi_rdata = { 31'h0, mpeg2_o_over, 11'h0, mpeg2_o_addr, 5'h0}; else if ( raddr_r >= 64'h01000000 ) // address >= 0x01000000 : read out buffer (i.e. MPEG2 output stream) case( raddr_r[4:3] ) 2'b00 : s_axi_rdata = out_buf_rdata[ 63: 0]; 2'b01 : s_axi_rdata = out_buf_rdata[127: 64]; 2'b10 : s_axi_rdata = out_buf_rdata[191:128]; 2'b11 : s_axi_rdata = out_buf_rdata[255:192]; endcase else s_axi_rdata = '0; always @ (posedge clk) begin mpeg2_sequence_stop <= 1'b0; mpeg2_i_en <= 1'b0; if ( mpeg2_o_en ) begin if ( mpeg2_o_addr == '1 ) mpeg2_o_over <= 1'b1; else mpeg2_o_addr <= mpeg2_o_addr + 16'h1; end if ( s_axi_wvalid & s_axi_wready ) begin if ( waddr == 64'h00000000 ) begin // address = 0x00000000 : write reset control register (reset control and sequence control) mpeg2_rstn <= s_axi_wdata[0]; mpeg2_sequence_stop <= s_axi_wdata[1]; end else if ( waddr == 64'h00000008 ) begin // address = 0x00000008 : write control register (video frame size) mpeg2_xsize16 <= s_axi_wdata[ 6: 0]; mpeg2_ysize16 <= s_axi_wdata[38:32]; end else if ( waddr == 64'h00000010 ) begin // address = 0x00000010 : write control register (out buffer control) mpeg2_o_addr <= '0; mpeg2_o_over <= '0; end else if ( waddr >= 64'h01000000 ) begin // address >= 0x01000000 : write video input data (i.e. raw YUV pixels) mpeg2_i_en <= 1'b1; { mpeg2_i_V2, mpeg2_i_Y3, mpeg2_i_U2, mpeg2_i_Y2, mpeg2_i_V0, mpeg2_i_Y1, mpeg2_i_U0, mpeg2_i_Y0 } <= s_axi_wdata; end end end ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // MPEG2 encoder instance ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// mpeg2encoder #( .XL ( 6 ), // determine the max horizontal pixel count. 4->256 pixels 5->512 pixels 6->1024 pixels 7->2048 pixels . .YL ( 6 ), // determine the max vertical pixel count. 4->256 pixels 5->512 pixels 6->1024 pixels 7->2048 pixels . .VECTOR_LEVEL ( 3 ), .Q_LEVEL ( 2 ) ) mpeg2encoder_i ( .rstn ( mpeg2_rstn ), .clk ( clk ), // Video sequence configuration interface. .i_xsize16 ( mpeg2_xsize16 ), .i_ysize16 ( mpeg2_ysize16 ), .i_pframes_count ( 8'd47 ), // Video sequence input pixel stream interface. In each clock cycle, this interface can input 4 adjacent pixels in a row. Pixel format is YUV 4:4:4, the module will convert it to YUV 4:2:0, then compress it to MPEG2 stream. .i_en ( mpeg2_i_en ), .i_Y0 ( mpeg2_i_Y0 ), .i_Y1 ( mpeg2_i_Y1 ), .i_Y2 ( mpeg2_i_Y2 ), .i_Y3 ( mpeg2_i_Y3 ), .i_U0 ( mpeg2_i_U0 ), .i_U1 ( mpeg2_i_U0 ), .i_U2 ( mpeg2_i_U2 ), .i_U3 ( mpeg2_i_U2 ), .i_V0 ( mpeg2_i_V0 ), .i_V1 ( mpeg2_i_V0 ), .i_V2 ( mpeg2_i_V2 ), .i_V3 ( mpeg2_i_V2 ), // Video sequence control interface. .i_sequence_stop ( mpeg2_sequence_stop ), .o_sequence_busy ( mpeg2_sequence_busy ), // Video sequence output MPEG2 stream interface. .o_en ( mpeg2_o_en ), .o_last ( mpeg2_o_last ), .o_data ( mpeg2_o_data ) ); endmodule