Skip to content

Commit c635392

Browse files
author
marqs
committed
add support for YPbPr extra_av_out
1 parent 3269b54 commit c635392

File tree

3 files changed

+355
-7
lines changed

3 files changed

+355
-7
lines changed

ossc_pro.qsf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ set_global_assignment -name VERILOG_FILE rtl/linebuf_top.v
644644
set_global_assignment -name VERILOG_FILE rtl/ir_rcv.v
645645
set_global_assignment -name VERILOG_FILE rtl/pwm_2ch.v
646646
set_global_assignment -name VERILOG_FILE rtl/dram_refresh_sched.v
647+
set_global_assignment -name VERILOG_FILE rtl/output_csc.v
647648
set_global_assignment -name SIP_FILE sys/simulation/sys.sip
648649
set_global_assignment -name QIP_FILE software/sys_controller/mem_init/meminit.qip
649650
set_global_assignment -name SIP_FILE software/sys_controller/mem_init/meminit.sip

rtl/ossc_pro.v

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -610,18 +610,39 @@ assign AUDMUX_o = ~audmux_sel;
610610
assign LS_DIR_o = (exp_sel == EXP_SEL_LEGAGY_IN) ? 2'b10 : 2'b11;
611611

612612
`ifdef EXTRA_AV_OUT
613+
// CSC for YPbPr
614+
wire [7:0] VGA_CSC_R_out, VGA_CSC_G_out, VGA_CSC_B_out;
615+
wire VGA_CSC_HSYNC_out, VGA_CSC_VSYNC_out, VGA_CSC_DE_out;
616+
output_csc csc_vga_inst (
617+
.PCLK_i(pclk_out),
618+
.reset_n(1'b1),
619+
.enable((exp_sel == EXP_SEL_EXTRA_OUT) & (extra_out_mode == EXTRA_OUT_YPbPr)),
620+
.R_i(R_out),
621+
.G_i(G_out),
622+
.B_i(B_out),
623+
.HSYNC_i(HSYNC_out),
624+
.VSYNC_i(VSYNC_out),
625+
.DE_i(DE_out),
626+
.R_o(VGA_CSC_R_out),
627+
.G_o(VGA_CSC_G_out),
628+
.B_o(VGA_CSC_B_out),
629+
.HSYNC_o(VGA_CSC_HSYNC_out),
630+
.VSYNC_o(VGA_CSC_VSYNC_out),
631+
.DE_o(VGA_CSC_DE_out),
632+
);
633+
613634
// VGA DAC
614635
reg [7:0] VGA_R, VGA_G, VGA_B, VGA_R_pre, VGA_G_pre, VGA_B_pre;
615636
reg VGA_HS, VGA_VS, VGA_SYNC_N, VGA_BLANK_N, VGA_HS_pre, VGA_VS_pre, VGA_SYNC_N_pre, VGA_BLANK_N_pre;
616637
always @(posedge pclk_out) begin
617638
if (exp_sel == EXP_SEL_EXTRA_OUT) begin
618-
VGA_R_pre <= R_out;
619-
VGA_G_pre <= G_out;
620-
VGA_B_pre <= B_out;
621-
VGA_HS_pre <= (extra_out_mode == EXTRA_OUT_RGBHV) ? HSYNC_out : ~(HSYNC_out ^ VSYNC_out);
622-
VGA_VS_pre <= (extra_out_mode == EXTRA_OUT_RGBHV) ? VSYNC_out : 1'b1;
623-
VGA_BLANK_N_pre <= DE_out;
624-
VGA_SYNC_N_pre <= (extra_out_mode >= EXTRA_OUT_RGsB) ? ~(HSYNC_out ^ VSYNC_out) : 1'b0;
639+
VGA_R_pre <= VGA_CSC_R_out;
640+
VGA_G_pre <= VGA_CSC_G_out;
641+
VGA_B_pre <= VGA_CSC_B_out;
642+
VGA_HS_pre <= (extra_out_mode == EXTRA_OUT_RGBHV) ? VGA_CSC_HSYNC_out : ~(VGA_CSC_HSYNC_out ^ VGA_CSC_VSYNC_out);
643+
VGA_VS_pre <= (extra_out_mode == EXTRA_OUT_RGBHV) ? VGA_CSC_VSYNC_out : 1'b1;
644+
VGA_BLANK_N_pre <= (extra_out_mode == EXTRA_OUT_YPbPr) ? 1'b1 : VGA_CSC_DE_out;
645+
VGA_SYNC_N_pre <= (extra_out_mode >= EXTRA_OUT_RGsB) ? ~(VGA_CSC_HSYNC_out ^ VGA_CSC_VSYNC_out) : 1'b0;
625646

626647
VGA_R <= VGA_R_pre;
627648
VGA_G <= VGA_G_pre;

rtl/output_csc.v

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
//
2+
// Copyright (C) 2024 Markus Hiienkari <mhiienka@niksula.hut.fi>
3+
//
4+
// This file is part of Open Source Scan Converter project.
5+
//
6+
// This program is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 3 of the License, or
9+
// (at your option) any later version.
10+
//
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
//
16+
// You should have received a copy of the GNU General Public License
17+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
//
19+
20+
module output_csc (
21+
input PCLK_i,
22+
input reset_n,
23+
input enable,
24+
input [7:0] R_i,
25+
input [7:0] G_i,
26+
input [7:0] B_i,
27+
input HSYNC_i,
28+
input VSYNC_i,
29+
input DE_i,
30+
output reg [7:0] R_o,
31+
output reg [7:0] G_o,
32+
output reg [7:0] B_o,
33+
output reg HSYNC_o,
34+
output reg VSYNC_o,
35+
output reg DE_o
36+
);
37+
38+
localparam PP_PL_START = 1;
39+
localparam PP_CSC_START = 0;
40+
localparam PP_CSC_LENGTH = 5;
41+
localparam PP_CSC_END = PP_CSC_START + PP_CSC_LENGTH;
42+
localparam PP_BIASMUX_START = PP_CSC_END;
43+
localparam PP_BIASMUX_LENGTH = 1;
44+
localparam PP_BIASMUX_END = PP_BIASMUX_START + PP_BIASMUX_LENGTH;
45+
localparam PP_PL_END = PP_BIASMUX_END;
46+
47+
reg HSYNC_pp[PP_PL_START:PP_CSC_END] /* synthesis ramstyle = "logic" */;
48+
reg VSYNC_pp[PP_PL_START:PP_CSC_END] /* synthesis ramstyle = "logic" */;
49+
reg DE_pp[PP_PL_START:PP_CSC_END] /* synthesis ramstyle = "logic" */;
50+
51+
// RGB->YPbPr709 decimal values * 2^15
52+
wire signed [17:0] Y_R_coeff = 6966;
53+
wire signed [17:0] Y_G_coeff = 23435;
54+
wire signed [17:0] Y_B_coeff = 2365;
55+
wire signed [17:0] Pb_R_coeff = -3754;
56+
wire signed [17:0] Pb_G_coeff = -12630;
57+
wire signed [17:0] Pb_B_coeff = 16384;
58+
wire signed [17:0] Pr_R_coeff = 16384;
59+
wire signed [17:0] Pr_G_coeff = -14882;
60+
wire signed [17:0] Pr_B_coeff = -1502;
61+
62+
wire signed [35:0] Y_R_pre, Y_G_pre, Y_B_pre;
63+
wire signed [35:0] Pb_R_pre, Pb_G_pre, Pb_B_pre;
64+
wire signed [35:0] Pr_R_pre, Pr_G_pre, Pr_B_pre;
65+
66+
reg signed [9:0] Y_R, Y_G, Y_B;
67+
reg signed [9:0] Pb_R, Pb_G, Pb_B;
68+
reg signed [9:0] Pr_R, Pr_G, Pr_B;
69+
70+
reg signed [9:0] Y_csc_sum, Pb_csc_sum, Pr_csc_sum;
71+
72+
reg [7:0] Y_csc, Pb_csc, Pr_csc;
73+
74+
always @(posedge PCLK_i) begin
75+
if (enable) begin
76+
// Cycle 1
77+
Y_R <= Y_R_pre[24:15];
78+
Y_G <= Y_G_pre[24:15];
79+
Y_B <= Y_B_pre[24:15];
80+
Pb_R <= Pb_R_pre[24:15];
81+
Pb_G <= Pb_G_pre[24:15];
82+
Pb_B <= Pb_B_pre[24:15];
83+
Pr_R <= Pr_R_pre[24:15];
84+
Pr_G <= Pr_G_pre[24:15];
85+
Pr_B <= Pr_B_pre[24:15];
86+
87+
// Cycle 2
88+
Y_csc_sum <= Y_R + Y_G + Y_B;
89+
Pb_csc_sum <= Pb_R + Pb_G + Pb_B + 10'd128;
90+
Pr_csc_sum <= Pr_R + Pr_G + Pr_B + 10'd128;
91+
92+
// Cycle 3
93+
if (Y_csc_sum[9] == 1'b1)
94+
Y_csc <= 8'h00;
95+
else if (Y_csc_sum[8] == 1'b1)
96+
Y_csc <= 8'hFF;
97+
else
98+
Y_csc <= Y_csc_sum[7:0];
99+
100+
if (Pb_csc_sum[9] == 1'b1)
101+
Pb_csc <= 8'h00;
102+
else if (Pb_csc_sum[8] == 1'b1)
103+
Pb_csc <= 8'hFF;
104+
else
105+
Pb_csc <= Pb_csc_sum[7:0];
106+
107+
if (Pr_csc_sum[9] == 1'b1)
108+
Pr_csc <= 8'h00;
109+
else if (Pr_csc_sum[8] == 1'b1)
110+
Pr_csc <= 8'hFF;
111+
else
112+
Pr_csc <= Pr_csc_sum[7:0];
113+
end
114+
end
115+
116+
// Pipeline stages 1-
117+
integer pp_idx;
118+
always @(posedge PCLK_i) begin
119+
HSYNC_pp[1] <= HSYNC_i;
120+
VSYNC_pp[1] <= VSYNC_i;
121+
DE_pp[1] <= DE_i;
122+
123+
for(pp_idx = PP_PL_START+1; pp_idx <= PP_CSC_END; pp_idx = pp_idx+1) begin
124+
HSYNC_pp[pp_idx] <= HSYNC_pp[pp_idx-1];
125+
VSYNC_pp[pp_idx] <= VSYNC_pp[pp_idx-1];
126+
DE_pp[pp_idx] <= DE_pp[pp_idx-1];
127+
end
128+
129+
R_o <= enable ? (DE_pp[PP_CSC_END] ? Pr_csc : 8'h80) : R_i;
130+
G_o <= enable ? (DE_pp[PP_CSC_END] ? Y_csc : 8'h00) : G_i;
131+
B_o <= enable ? (DE_pp[PP_CSC_END] ? Pb_csc : 8'h80) : B_i;
132+
HSYNC_o <= enable ? HSYNC_pp[PP_CSC_END] : HSYNC_i;
133+
VSYNC_o <= enable ? VSYNC_pp[PP_CSC_END] : VSYNC_i;
134+
DE_o <= enable ? DE_pp[PP_CSC_END] : DE_i;
135+
end
136+
137+
lpm_mult csc_mult_component_0 (
138+
// Inputs
139+
.dataa ({10'h0, R_i}),
140+
.datab (Y_R_coeff),
141+
.aclr (1'b0),
142+
.clken (enable),
143+
.clock (PCLK_i),
144+
145+
// Outputs
146+
.result (Y_R_pre),
147+
.sum (1'b0)
148+
);
149+
defparam
150+
csc_mult_component_0.lpm_widtha = 18,
151+
csc_mult_component_0.lpm_widthb = 18,
152+
csc_mult_component_0.lpm_widthp = 36,
153+
csc_mult_component_0.lpm_widths = 1,
154+
csc_mult_component_0.lpm_type = "LPM_MULT",
155+
csc_mult_component_0.lpm_representation = "SIGNED",
156+
csc_mult_component_0.lpm_hint = "LPM_PIPELINE=2,MAXIMIZE_SPEED=5";
157+
158+
lpm_mult csc_mult_component_1 (
159+
// Inputs
160+
.dataa ({10'h0, G_i}),
161+
.datab (Y_G_coeff),
162+
.aclr (1'b0),
163+
.clken (enable),
164+
.clock (PCLK_i),
165+
166+
// Outputs
167+
.result (Y_G_pre),
168+
.sum (1'b0)
169+
);
170+
defparam
171+
csc_mult_component_1.lpm_widtha = 18,
172+
csc_mult_component_1.lpm_widthb = 18,
173+
csc_mult_component_1.lpm_widthp = 36,
174+
csc_mult_component_1.lpm_widths = 1,
175+
csc_mult_component_1.lpm_type = "LPM_MULT",
176+
csc_mult_component_1.lpm_representation = "SIGNED",
177+
csc_mult_component_1.lpm_hint = "LPM_PIPELINE=2,MAXIMIZE_SPEED=5";
178+
179+
lpm_mult csc_mult_component_2 (
180+
// Inputs
181+
.dataa ({10'h0, B_i}),
182+
.datab (Y_B_coeff),
183+
.aclr (1'b0),
184+
.clken (enable),
185+
.clock (PCLK_i),
186+
187+
// Outputs
188+
.result (Y_B_pre),
189+
.sum (1'b0)
190+
);
191+
defparam
192+
csc_mult_component_2.lpm_widtha = 18,
193+
csc_mult_component_2.lpm_widthb = 18,
194+
csc_mult_component_2.lpm_widthp = 36,
195+
csc_mult_component_2.lpm_widths = 1,
196+
csc_mult_component_2.lpm_type = "LPM_MULT",
197+
csc_mult_component_2.lpm_representation = "SIGNED",
198+
csc_mult_component_2.lpm_hint = "LPM_PIPELINE=2,MAXIMIZE_SPEED=5";
199+
200+
lpm_mult csc_mult_component_3 (
201+
// Inputs
202+
.dataa ({10'h0, R_i}),
203+
.datab (Pb_R_coeff),
204+
.aclr (1'b0),
205+
.clken (enable),
206+
.clock (PCLK_i),
207+
208+
// Outputs
209+
.result (Pb_R_pre),
210+
.sum (1'b0)
211+
);
212+
defparam
213+
csc_mult_component_3.lpm_widtha = 18,
214+
csc_mult_component_3.lpm_widthb = 18,
215+
csc_mult_component_3.lpm_widthp = 36,
216+
csc_mult_component_3.lpm_widths = 1,
217+
csc_mult_component_3.lpm_type = "LPM_MULT",
218+
csc_mult_component_3.lpm_representation = "SIGNED",
219+
csc_mult_component_3.lpm_hint = "LPM_PIPELINE=2,MAXIMIZE_SPEED=5";
220+
221+
lpm_mult csc_mult_component_4 (
222+
// Inputs
223+
.dataa ({10'h0, G_i}),
224+
.datab (Pb_G_coeff),
225+
.aclr (1'b0),
226+
.clken (enable),
227+
.clock (PCLK_i),
228+
229+
// Outputs
230+
.result (Pb_G_pre),
231+
.sum (1'b0)
232+
);
233+
defparam
234+
csc_mult_component_4.lpm_widtha = 18,
235+
csc_mult_component_4.lpm_widthb = 18,
236+
csc_mult_component_4.lpm_widthp = 36,
237+
csc_mult_component_4.lpm_widths = 1,
238+
csc_mult_component_4.lpm_type = "LPM_MULT",
239+
csc_mult_component_4.lpm_representation = "SIGNED",
240+
csc_mult_component_4.lpm_hint = "LPM_PIPELINE=2,MAXIMIZE_SPEED=5";
241+
242+
lpm_mult csc_mult_component_5 (
243+
// Inputs
244+
.dataa ({10'h0, B_i}),
245+
.datab (Pb_B_coeff),
246+
.aclr (1'b0),
247+
.clken (enable),
248+
.clock (PCLK_i),
249+
250+
// Outputs
251+
.result (Pb_B_pre),
252+
.sum (1'b0)
253+
);
254+
defparam
255+
csc_mult_component_5.lpm_widtha = 18,
256+
csc_mult_component_5.lpm_widthb = 18,
257+
csc_mult_component_5.lpm_widthp = 36,
258+
csc_mult_component_5.lpm_widths = 1,
259+
csc_mult_component_5.lpm_type = "LPM_MULT",
260+
csc_mult_component_5.lpm_representation = "SIGNED",
261+
csc_mult_component_5.lpm_hint = "LPM_PIPELINE=2,MAXIMIZE_SPEED=5";
262+
263+
lpm_mult csc_mult_component_6 (
264+
// Inputs
265+
.dataa ({10'h0, R_i}),
266+
.datab (Pr_R_coeff),
267+
.aclr (1'b0),
268+
.clken (enable),
269+
.clock (PCLK_i),
270+
271+
// Outputs
272+
.result (Pr_R_pre),
273+
.sum (1'b0)
274+
);
275+
defparam
276+
csc_mult_component_6.lpm_widtha = 18,
277+
csc_mult_component_6.lpm_widthb = 18,
278+
csc_mult_component_6.lpm_widthp = 36,
279+
csc_mult_component_6.lpm_widths = 1,
280+
csc_mult_component_6.lpm_type = "LPM_MULT",
281+
csc_mult_component_6.lpm_representation = "SIGNED",
282+
csc_mult_component_6.lpm_hint = "LPM_PIPELINE=2,MAXIMIZE_SPEED=5";
283+
284+
lpm_mult csc_mult_component_7 (
285+
// Inputs
286+
.dataa ({10'h0, G_i}),
287+
.datab (Pr_G_coeff),
288+
.aclr (1'b0),
289+
.clken (enable),
290+
.clock (PCLK_i),
291+
292+
// Outputs
293+
.result (Pr_G_pre),
294+
.sum (1'b0)
295+
);
296+
defparam
297+
csc_mult_component_7.lpm_widtha = 18,
298+
csc_mult_component_7.lpm_widthb = 18,
299+
csc_mult_component_7.lpm_widthp = 36,
300+
csc_mult_component_7.lpm_widths = 1,
301+
csc_mult_component_7.lpm_type = "LPM_MULT",
302+
csc_mult_component_7.lpm_representation = "SIGNED",
303+
csc_mult_component_7.lpm_hint = "LPM_PIPELINE=2,MAXIMIZE_SPEED=5";
304+
305+
lpm_mult csc_mult_component_8 (
306+
// Inputs
307+
.dataa ({10'h0, B_i}),
308+
.datab (Pr_B_coeff),
309+
.aclr (1'b0),
310+
.clken (enable),
311+
.clock (PCLK_i),
312+
313+
// Outputs
314+
.result (Pr_B_pre),
315+
.sum (1'b0)
316+
);
317+
defparam
318+
csc_mult_component_8.lpm_widtha = 18,
319+
csc_mult_component_8.lpm_widthb = 18,
320+
csc_mult_component_8.lpm_widthp = 36,
321+
csc_mult_component_8.lpm_widths = 1,
322+
csc_mult_component_8.lpm_type = "LPM_MULT",
323+
csc_mult_component_8.lpm_representation = "SIGNED",
324+
csc_mult_component_8.lpm_hint = "LPM_PIPELINE=2,MAXIMIZE_SPEED=5";
325+
326+
endmodule

0 commit comments

Comments
 (0)