/////////////////////////////////////////////////////////////////////
////                                                             ////
////  WISHBONE rev.B2 compliant enhanced VGA/LCD Core            ////
////  Hardware Cursor Processor                                  ////
////                                                             ////
////  Author: Richard Herveille                                  ////
////          richard@asics.ws                                   ////
////          www.asics.ws                                       ////
////                                                             ////
////  Downloaded from: http://www.opencores.org/projects/vga_lcd ////
////                                                             ////
/////////////////////////////////////////////////////////////////////
////                                                             ////
//// Copyright (C) 2002 Richard Herveille                        ////
////                    richard@asics.ws                         ////
////                                                             ////
//// This source file may be used and distributed without        ////
//// restriction provided that this copyright statement is not   ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer.////
////                                                             ////
////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
//// POSSIBILITY OF SUCH DAMAGE.                                 ////
////                                                             ////
/////////////////////////////////////////////////////////////////////

//  CVS Log
//
//  $Id: vga_curproc.v,v 1.4 2003-05-07 09:48:54 rherveille Exp $
//
//  $Date: 2003-05-07 09:48:54 $
//  $Revision: 1.4 $
//  $Author: rherveille $
//  $Locker:  $
//  $State: Exp $
//
// Change History:
//               $Log: not supported by cvs2svn $
//               Revision 1.3  2002/03/04 16:05:52  rherveille
//               Added hardware cursor support to wishbone master.
//               Added provision to turn-off 3D cursors.
//               Fixed some minor bugs.
//
//               Revision 1.2  2002/03/04 11:01:59  rherveille
//               Added 64x64pixels 4bpp hardware cursor support.
//
//               Revision 1.1  2002/02/16 10:40:00  rherveille
//               Some minor bug-fixes.
//               Changed vga_ssel into vga_curproc (cursor processor).
//
//               Revision 1.1  2002/02/07 05:42:10  rherveille
//               Fixed some bugs discovered by modified testbench
//               Removed / Changed some strange logic constructions
//               Started work on hardware cursor support (not finished yet)
//               Changed top-level name to vga_enh_top.v
//

//synopsys translate_off
`include "timescale.v"
//synopsys translate_on

module vga_curproc (clk, rst_i, Thgate, Tvgate, idat, idat_wreq, 
	cursor_xy, cursor_en, cursor_res, 
	cursor_wadr, cursor_wdat, cursor_we,
	cc_adr_o, cc_dat_i,
	rgb_fifo_wreq, rgb);

	//
	// inputs & outputs
	//

	// wishbone signals
	input         clk;           // master clock input
	input         rst_i;         // synchronous active high reset

	// image size
	input [15:0] Thgate, Tvgate; // horizontal/vertical gate
	// image data
	input [23:0] idat;           // image data input
	input        idat_wreq;      // image data write request

	// cursor data
	input [31:0] cursor_xy;      // cursor (x,y)
	input        cursor_en;      // cursor enable (on/off)
	input        cursor_res;     // cursor resolution (32x32 or 64x64 pixels)
	input [ 8:0] cursor_wadr;    // cursor buffer write address
	input [31:0] cursor_wdat;    // cursor buffer write data
	input        cursor_we;      // cursor buffer write enable

	// color registers interface
	output [ 3:0] cc_adr_o;      // cursor color registers address
	reg  [ 3:0] cc_adr_o;    
	input  [15:0] cc_dat_i;      // cursor color registers data

	// rgb-fifo connections
	output        rgb_fifo_wreq; // rgb-out write request
	reg        rgb_fifo_wreq;
	output [23:0] rgb;           // rgb data output
	reg [23:0] rgb;

	//
	// variable declarations
	//
	reg         dcursor_en, ddcursor_en, dddcursor_en;
	reg  [15:0] xcnt, ycnt;
	wire        xdone, ydone;
	wire [15:0] cursor_x, cursor_y;
	wire        cursor_isalpha;
	reg  [15:0] cdat, dcdat;
	wire [ 7:0] cursor_r, cursor_g, cursor_b, cursor_alpha;
	reg         inbox_x, inbox_y;
	wire        inbox;
	reg         dinbox, ddinbox, dddinbox;

	reg  [23:0] didat, ddidat, dddidat;
	reg         didat_wreq, ddidat_wreq;
	wire [31:0] cbuf_q;
	reg  [11:0] cbuf_ra;
	reg  [ 2:0] dcbuf_ra;
	wire [ 8:0] cbuf_a;

	reg         store1, store2;

	//
	// module body
	//

	//
	// generate x-y counters
	always@(posedge clk)
		if(rst_i || xdone)
			xcnt <= #1 16'h0;
		else if (idat_wreq)
			xcnt <= #1 xcnt + 16'h1;

	assign xdone = (xcnt == Thgate) && idat_wreq;

	always@(posedge clk)
		if(rst_i || ydone)
			ycnt <= #1 16'h0;
		else if (xdone)
			ycnt <= #1 ycnt + 16'h1;

	assign ydone = (ycnt == Tvgate) && xdone;


	// decode cursor (x,y)
	assign cursor_x = cursor_xy[15: 0];
	assign cursor_y = cursor_xy[31:16];

	//
	// generate inbox signals
	always@(posedge clk)
		begin
			inbox_x <= #1 (xcnt >= cursor_x) && (xcnt < (cursor_x + (cursor_res ? 16'h7f : 16'h1f) ));
			inbox_y <= #1 (ycnt >= cursor_y) && (ycnt < (cursor_y + (cursor_res ? 16'h7f : 16'h1f) ));
		end

	assign inbox = inbox_x && inbox_y;

	always@(posedge clk)
		dinbox <= #1 inbox;

	always@(posedge clk)
		if (didat_wreq)
			ddinbox <= #1 dinbox;

	always@(posedge clk)
		dddinbox <= #1 ddinbox;

	//
	// generate cursor buffer address counter
	always@(posedge clk)
		if (!cursor_en || ydone)
			cbuf_ra <= #1 12'h0;
		else if (inbox && idat_wreq)
			cbuf_ra <= #1 cbuf_ra +12'h1;

	always@(posedge clk)
		dcbuf_ra <= #1 cbuf_ra[2:0];

	assign cbuf_a = cursor_we ? cursor_wadr : cursor_res ? cbuf_ra[11:3] : cbuf_ra[9:1];

	// hookup local cursor memory (generic synchronous single port memory)
	// cursor memory should never be written to/read from at the same time
	generic_spram #(9, 32) cbuf(
		.clk(clk),
		.rst(1'b0),       // no reset
		.ce(1'b1),        // always enable memory
		.we(cursor_we),
		.oe(1'b1),        // always output data
		.addr(cbuf_a),
		.di(cursor_wdat),
		.dout(cbuf_q)
	);

	//
	// decode cursor data for 32x32x16bpp mode
	always@(posedge clk)
		if (didat_wreq)
			cdat <= #1 dcbuf_ra[0] ? cbuf_q[31:16] : cbuf_q[15:0];

	always@(posedge clk)
		dcdat <= #1 cdat;

	//
	// decode cursor data for 64x64x4bpp mode

	// generate cursor-color address
	always@(posedge clk)
		if (didat_wreq)
			case (dcbuf_ra)
				3'b000: cc_adr_o <= cbuf_q[ 3: 0];
				3'b001: cc_adr_o <= cbuf_q[ 7: 4];
				3'b010: cc_adr_o <= cbuf_q[11: 8];
				3'b011: cc_adr_o <= cbuf_q[15:12];
				3'b100: cc_adr_o <= cbuf_q[19:16];
				3'b101: cc_adr_o <= cbuf_q[23:20];
				3'b110: cc_adr_o <= cbuf_q[27:24];
				3'b111: cc_adr_o <= cbuf_q[31:28];
			endcase

	//
	// generate cursor colors
	assign cursor_isalpha =  cursor_res ? cc_dat_i[15]    : dcdat[15];
	assign cursor_alpha   =  cursor_res ? cc_dat_i[7:0]   : dcdat[7:0];
	assign cursor_r       = {cursor_res ? cc_dat_i[14:10] : dcdat[14:10], 3'h0};
	assign cursor_g       = {cursor_res ? cc_dat_i[ 9: 5] : dcdat[ 9: 5], 3'h0};
	assign cursor_b       = {cursor_res ? cc_dat_i[ 4: 0] : dcdat[ 4: 0], 3'h0};

	//
	// delay image data
	always@(posedge clk)
		didat <= #1 idat;

	always@(posedge clk)
		if (didat_wreq)
			ddidat <= #1 didat;

	always@(posedge clk)
		dddidat <= #1 ddidat;

	always@(posedge clk)
		begin
			didat_wreq  <= #1 idat_wreq;
			ddidat_wreq <= #1 didat_wreq;
		end

	//
	// generate selection unit
	always@(posedge clk)
		dcursor_en <= #1 cursor_en;

	always@(posedge clk)
		if (didat_wreq)
			ddcursor_en <= #1 dcursor_en;

	always@(posedge clk)
		dddcursor_en <= #1 ddcursor_en;

	// Alpha blending:
	// rgb = (rgb1 * alhpa1) + (rgb2 * alpha2)
	// We generate an alpha mixer (alpha1 + alpha2 = 1)
	// rgb = (alpha1)(rgb1) + (1-alpha1)(rgb2)
	// We always mix to black (rgb2 = 0)
	// rgb = (alpha1)(rgb1)
	always@(posedge clk)
		if (ddidat_wreq)
			if (!dddcursor_en || !dddinbox)
				rgb <= #1 dddidat;
			else if (cursor_isalpha)
				`ifdef VGA_HWC_3D
					rgb <= #1 dddidat * cursor_alpha;
				`else
					rgb <= #1 dddidat;
				`endif
			else
				rgb <= #1 {cursor_r, cursor_g, cursor_b};

	//
	// generate write request signal
	always@(posedge clk)
		if (rst_i)
		begin
			store1 <= #1 1'b0;
			store2 <= #1 1'b0;
		end
		else
		begin
			store1 <= #1  didat_wreq           | store1;
			store2 <= #1 (didat_wreq & store1) | store2;
		end

	// skip 2 idat_wreq signal, to keep in pace with rgb_fifo_full signal
	always@(posedge clk)
		rgb_fifo_wreq <= #1 ddidat_wreq & store2;

endmodule
