diff --git a/cores/c16/c16_mist.qsf b/cores/c16/c16_mist.qsf index 46aff41..85f6097 100644 --- a/cores/c16/c16_mist.qsf +++ b/cores/c16/c16_mist.qsf @@ -352,4 +352,5 @@ set_global_assignment -name VHDL_FILE t65/T65_MCode.vhd set_global_assignment -name VHDL_FILE t65/T65_ALU.vhd set_global_assignment -name VHDL_FILE t65/T65.vhd set_global_assignment -name SIGNALTAP_FILE output_files/stp1.stp +set_global_assignment -name SYSTEMVERILOG_FILE rgb2ypbpr.sv set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/cores/c16/c16_mist.v b/cores/c16/c16_mist.v index dead4c0..82ea447 100644 --- a/cores/c16/c16_mist.v +++ b/cores/c16/c16_mist.v @@ -83,6 +83,7 @@ parameter CONF_STR_LEN = 8+17+20+28+18+9; // the status register is controlled by the on screen display (OSD) wire [7:0] status; wire tv15khz; +wire ypbpr; wire scanlines = status[2]; wire joystick_swap = status[3]; wire memory_16k = status[4]; @@ -238,6 +239,7 @@ user_io #(.STRLEN(CONF_STR_LEN)) user_io ( .SPI_MOSI ( SPI_DI ), .scandoubler_disable ( tv15khz ), + .ypbpr ( ypbpr ), .buttons ( buttons ), .joystick_0 ( js0 ), @@ -414,6 +416,8 @@ wire osd_vs_in = tv15khz?!c16_vs:video_vs; wire osd_clk = tv15khz?clk7:clk14; +wire [5:0] red, green, blue; + // include the on screen display osd #(11,0,5) osd ( .clk_sys ( clk28 ), @@ -430,17 +434,32 @@ osd #(11,0,5) osd ( .hs_in ( osd_hs_in ), .vs_in ( osd_vs_in ), - .red_out ( VGA_R ), - .green_out ( VGA_G ), - .blue_out ( VGA_B ) + .red_out ( red ), + .green_out ( green ), + .blue_out ( blue ) ); +wire [5:0] y, pb, pr; +rgb2ypbpr rgb2ypbpr ( + .red ( red ), + .green ( green ), + .blue ( blue ), + + .y ( y ), + .pb ( pb ), + .pr ( pr ) +); + +assign VGA_R = ypbpr ? pr : red; +assign VGA_G = ypbpr ? y : green; +assign VGA_B = ypbpr ? pb : blue; + // in 15khz tv mode directly use the c16's composite sync. Otherwise the VGA // output is driven from the sync signals generated by the scan doubler. In // 15khz mode the VS signal is used as the RGB detect signal on the SCART // connector and thus needs to be driven to 1 -assign VGA_HS = tv15khz?c16_cs:video_hs; -assign VGA_VS = tv15khz?1'b1:video_vs; +assign VGA_HS = tv15khz?c16_cs:ypbpr ? (video_hs ^ video_vs) : video_hs; +assign VGA_VS = (tv15khz || ypbpr)?1'b1:video_vs; wire video_hs, video_vs; wire [5:0] video_r; diff --git a/cores/c16/rgb2ypbpr.sv b/cores/c16/rgb2ypbpr.sv new file mode 100644 index 0000000..1e1662e --- /dev/null +++ b/cores/c16/rgb2ypbpr.sv @@ -0,0 +1,55 @@ +module rgb2ypbpr ( + input [5:0] red, + input [5:0] green, + input [5:0] blue, + + output [5:0] y, + output [5:0] pb, + output [5:0] pr +); + +wire [5:0] yuv_full[225] = '{ + 6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1, + 6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4, + 6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6, + 6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8, + 6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11, + 6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13, + 6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15, + 6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17, + 6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20, + 6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22, + 6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24, + 6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27, + 6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29, + 6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31, + 6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33, + 6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36, + 6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38, + 6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40, + 6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42, + 6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45, + 6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47, + 6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49, + 6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52, + 6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54, + 6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56, + 6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58, + 6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61, + 6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63, + 6'd63 +}; + +wire [18:0] y_8 = 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}); +wire [18:0] pb_8 = 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}); +wire [18:0] pr_8 = 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0}); + +wire [7:0] y_i = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8]; +wire [7:0] pb_i = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8]; +wire [7:0] pr_i = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8]; + +assign pr = yuv_full[pr_i - 8'd16]; +assign y = yuv_full[y_i - 8'd16]; +assign pb = yuv_full[pb_i - 8'd16]; + +endmodule