//============================================================================ // // HDMI Lite output module // Copyright (C) 2017 Sorgelig // // This program 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 2 of the License, or (at your option) // any later version. // //============================================================================ module hdmi_lite ( input reset, input clk_video, input ce_pixel, input video_vs, input video_de, input [23:0] video_d, input clk_hdmi, input hdmi_hde, input hdmi_vde, output reg hdmi_de, output [23:0] hdmi_d, input [11:0] screen_w, input [11:0] screen_h, input quadbuf, // 0-3 => scale 1-4 input [1:0] scale_x, input [1:0] scale_y, input scale_auto, input clk_vbuf, output [27:0] vbuf_address, input [127:0] vbuf_readdata, output [127:0] vbuf_writedata, output [7:0] vbuf_burstcount, output [15:0] vbuf_byteenable, input vbuf_waitrequest, input vbuf_readdatavalid, output reg vbuf_read, output reg vbuf_write ); localparam [7:0] burstsz = 64; reg [1:0] nbuf = 0; wire [27:0] read_buf = {4'd2, 3'b000, (quadbuf ? nbuf-2'd1 : 2'b00), 19'd0}; wire [27:0] write_buf = {4'd2, 3'b000, (quadbuf ? nbuf+2'd1 : 2'b00), 19'd0}; assign vbuf_address = vbuf_write ? vbuf_waddress : vbuf_raddress; assign vbuf_burstcount = vbuf_write ? vbuf_wburstcount : vbuf_rburstcount; wire [95:0] hf_out; wire [7:0] hf_usedw; reg hf_reset = 0; vbuf_fifo out_fifo ( .aclr(hf_reset), .wrclk(clk_vbuf), .wrreq(vbuf_readdatavalid), .data({vbuf_readdata[96+:24],vbuf_readdata[64+:24],vbuf_readdata[32+:24],vbuf_readdata[0+:24]}), .wrusedw(hf_usedw), .rdclk(~clk_hdmi), .rdreq(hf_rdreq), .q(hf_out) ); reg [11:0] rd_stride; wire [7:0] rd_burst = (burstsz < rd_stride) ? burstsz : rd_stride[7:0]; reg [27:0] vbuf_raddress; reg [7:0] vbuf_rburstcount; always @(posedge clk_vbuf) begin reg [18:0] rdcnt; reg [7:0] bcnt; reg vde1, vde2; reg [1:0] mcnt; reg [1:0] my; reg [18:0] fsz; reg [11:0] strd; vde1 <= hdmi_vde; vde2 <= vde1; if(vbuf_readdatavalid) begin rdcnt <= rdcnt + 1'd1; if(bcnt) bcnt <= bcnt - 1'd1; vbuf_raddress <= vbuf_raddress + 1'd1; end if(!bcnt && reading) reading <= 0; vbuf_read <= 0; if(~vbuf_waitrequest) begin if(!hf_reset && rdcnt=off_x) && (x<(vh_width+off_x)) && (y>=off_y) && (y<(vh_height+off_y)) && !hload && !pcnt; wire de_in = hdmi_hde & hdmi_vde; always @(posedge clk_hdmi) begin reg [71:0] px_out; reg [1:0] mx; reg vde; vde <= hdmi_vde; if(vde & ~hdmi_vde) begin off_x <= (screen_w>v_width) ? (screen_w - v_width)>>1 : 12'd0; off_y <= (screen_h>v_height) ? (screen_h - v_height)>>1 : 12'd0; vh_height <= v_height; vh_width <= v_width; mx <= mult_x; end pcnt <= pcnt + 1'd1; if(pcnt == mx) begin pcnt <= 0; hload <= hload + 1'd1; end if(~de_in || x (screen_h/2)) ? 2'b00 : (video_y > (screen_h/3)) ? 2'b01 : (video_y > (screen_h/4)) ? 2'b10 : 2'b11; wire [1:0] tm_x = (l1_width > (screen_w/2)) ? 2'b00 : (l1_width > (screen_w/3)) ? 2'b01 : (l1_width > (screen_w/4)) ? 2'b10 : 2'b11; wire [1:0] tm_xy = (tm_x < tm_y) ? tm_x : tm_y; wire [1:0] tmf_y = scale_auto ? tm_xy : scale_y; wire [1:0] tmf_x = scale_auto ? tm_xy : scale_x; wire [11:0] t_height = video_y + (tmf_y[0] ? video_y : 12'd0) + (tmf_y[1] ? video_y<<1 : 12'd0); wire [11:0] t_width = l1_width + (tmf_x[0] ? l1_width : 12'd0) + (tmf_x[1] ? l1_width<<1 : 12'd0); wire [23:0] t_fsz = l1_stride * t_height; reg [11:0] l1_width; reg [11:0] l1_stride; always @(posedge clk_video) begin reg [7:0] loaded = 0; reg [11:0] strd = 0; reg old_de = 0; reg old_vs = 0; old_vs <= video_vs; if(~old_vs & video_vs) begin cur_addr<= write_buf; video_x <= 0; video_y <= 0; loaded <= 0; strd <= 0; nbuf <= nbuf + 1'd1; stride <= l1_stride; framesz <= t_fsz[18:0]; v_height<= t_height; v_width <= t_width; mult_x <= tmf_x; mult_y <= tmf_y; end if(pix_wr) begin case(video_x[1:0]) 0: pix_acc <= video_d; // zeroes upper bits too 1: pix_acc[47:24] <= video_d; 2: pix_acc[71:48] <= video_d; 3: loaded <= loaded + 1'd1; endcase if(video_x= burstsz) || (old_de & ~video_de)) begin if(loaded + infifo_tail) begin flush_size <= loaded + infifo_tail; flush_addr <= cur_addr; flush_req <= ~flush_req; loaded <= 0; strd <= strd + loaded; end cur_addr <= cur_addr + loaded + infifo_tail; if(~video_de) begin if(video_y