You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
11 KiB
Systemverilog
288 lines
11 KiB
Systemverilog
|
|
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
|
|
|
|
|