summaryrefslogtreecommitdiff
path: root/rtl/gfx/gfx_scanout_dac.sv
blob: 5c80d2bd3b5d6046c8cb39cf156d58779e3588c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
`include "gfx/gfx_defs.sv"

module gfx_scanout_dac
(
	input  logic     clk,
	                 rst_n,

	input  logic     enable_clear,
	input  rgb24     clear_color,

	input  logic     mask_fifo_out,
	input  vram_word fb_fifo_out,
	input  logic     in_valid,
	output logic     in_ready,

	input  logic     scan_ready,
	output logic     scan_valid,
	                 scan_endofpacket,
	                 scan_startofpacket,
	output rgb30     scan_data,

	output logic     vsync
);

	logic dac_valid, half, half_mask, stall, endofpacket, startofpacket;
	rgb24 pixel;
	rgb32 fifo_pixel;
	vram_word msw, lsw;
	half_coord next_addr;
	linear_coord max_addr, pixel_addr;

	struct packed
	{
		logic endofpacket,
		      startofpacket;
		rgb30 pixel;
	} skid_in, skid_out;

	assign scan_data = skid_out.pixel;
	assign scan_endofpacket = skid_out.endofpacket;
	assign scan_startofpacket = skid_out.startofpacket;

	assign max_addr = `GFX_X_RES * `GFX_Y_RES - 1;

	assign fifo_pixel = {msw, lsw};
	assign skid_in.endofpacket = endofpacket;
	assign skid_in.startofpacket = startofpacket;

	function color10 dac_color(color8 in);
		dac_color = {in, {2{in[0]}}};
	endfunction

	assign skid_in.pixel.r = dac_color(pixel.r);
	assign skid_in.pixel.g = dac_color(pixel.g);
	assign skid_in.pixel.b = dac_color(pixel.b);

	always_comb begin
		// Descarta fifo_pixel.a
		pixel.r = fifo_pixel.r;
		pixel.g = fifo_pixel.g;
		pixel.b = fifo_pixel.b;

		if (!half_mask)
			pixel = clear_color;
	end

	gfx_skid_flow flow
	(
		.in_valid(dac_valid),
		.out_ready(scan_ready),
		.out_valid(scan_valid),
		.*
	);

	gfx_skid_buf #(.WIDTH($bits(skid_in))) skid
	(
		.in(skid_in),
		.out(skid_out),
		.*
	);

	always_ff @(posedge clk or negedge rst_n)
		if (!rst_n) begin
			half <= 0;
			vsync <= 0;
			dac_valid <= 0;
			pixel_addr <= 0;
		end else begin
			vsync <= 0;
			if (in_ready && dac_valid) begin
				vsync <= skid_in.endofpacket;
				dac_valid <= 0;
			end

			if (in_ready && in_valid) begin
				half <= !half;
				dac_valid <= half;

				if (half) begin
					pixel_addr <= pixel_addr + 1;
					if (pixel_addr == max_addr)
						pixel_addr <= 0;
				end
			end
		end

	always_ff @(posedge clk)
		if (in_ready && in_valid) begin
			lsw <= msw;
			msw <= fb_fifo_out;
			half_mask <= mask_fifo_out;

			endofpacket <= pixel_addr == max_addr;
			startofpacket <= pixel_addr == 0;
		end

endmodule