Update sys.

This commit is contained in:
Sorgelig 2023-03-02 01:08:42 +08:00
parent 8dd279eef3
commit 98b7a395ce
11 changed files with 3222 additions and 3067 deletions

View File

@ -52,13 +52,14 @@ module emu
output VGA_F1,
output [1:0] VGA_SL,
output VGA_SCALER, // Force VGA scaler
output VGA_DISABLE, // analog out is off
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
output HDMI_FREEZE,
`ifdef MISTER_FB
// Use framebuffer in DDRAM (USE_FB=1 in qsf)
// Use framebuffer in DDRAM
// FB_FORMAT:
// [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp
// [3] : 0=16bits 565 1=16bits 1555
@ -185,6 +186,7 @@ assign LED_POWER = 0;
assign BUTTONS = 0;
assign VGA_SCALER= 0;
assign HDMI_FREEZE = 0;
assign VGA_DISABLE = 0;
wire [1:0] ar = status[8:7];
video_freak video_freak

File diff suppressed because it is too large Load Diff

View File

@ -1,239 +0,0 @@
module hdmi_config
(
// Host Side
input iCLK,
input iRST_N,
input dvi_mode,
input audio_96k,
input [1:0] limited,
input ypbpr,
output reg done,
// I2C Side
output I2C_SCL,
inout I2C_SDA
);
// Internal Registers/Wires
reg mI2C_GO = 0;
wire mI2C_END;
wire mI2C_ACK;
reg [15:0] LUT_DATA;
reg [7:0] LUT_INDEX = 0;
i2c #(50_000_000, 20_000) i2c_av
(
.CLK(iCLK),
.I2C_SCL(I2C_SCL), // I2C CLOCK
.I2C_SDA(I2C_SDA), // I2C DATA
.I2C_ADDR('h39), // 0x39 is the Slave Address of the ADV7513 chip!
.I2C_WLEN(1),
.I2C_WDATA1(init_data[LUT_INDEX][15:8]), // SUB_ADDR
.I2C_WDATA2(init_data[LUT_INDEX][7:0]), // DATA
.START(mI2C_GO), // START transfer
.READ(0),
.END(mI2C_END), // END transfer
.ACK(mI2C_ACK) // ACK
);
////////////////////// Config Control ////////////////////////////
always@(posedge iCLK or negedge iRST_N) begin
reg [1:0] mSetup_ST = 0;
if(!iRST_N) begin
LUT_INDEX <= 0;
mSetup_ST <= 0;
mI2C_GO <= 0;
done <= 0;
end else begin
if(init_data[LUT_INDEX] != 16'hFFFF) begin
case(mSetup_ST)
0: begin
mI2C_GO <= 1;
mSetup_ST <= 1;
end
1: if(~mI2C_END) mSetup_ST <= 2;
2: begin
mI2C_GO <= 0;
if(mI2C_END) begin
mSetup_ST <= 0;
if(!mI2C_ACK) LUT_INDEX <= LUT_INDEX + 8'd1;
end
end
endcase
end
else done <= 1;
end
end
////////////////////////////////////////////////////////////////////
///////////////////// Config Data LUT //////////////////////////
wire [15:0] init_data[82] =
'{
16'h9803, // ADI required Write.
{8'hD6, 8'b1100_0000}, // [7:6] HPD Control...
// 00 = HPD is from both HPD pin or CDC HPD
// 01 = HPD is from CDC HPD
// 10 = HPD is from HPD pin
// 11 = HPD is always high
16'h4110, // Power Down control
16'h9A70, // ADI required Write.
16'h9C30, // ADI required Write.
{8'h9D, 8'b0110_0001}, // [7:4] must be b0110!.
// [3:2] b00 = Input clock not divided. b01 = Clk divided by 2. b10 = Clk divided by 4. b11 = invalid!
// [1:0] must be b01!
16'hA2A4, // ADI required Write.
16'hA3A4, // ADI required Write.
16'hE0D0, // ADI required Write.
16'h35_40,
16'h36_D9,
16'h37_0A,
16'h38_00,
16'h39_2D,
16'h3A_00,
{8'h16, 8'b0011_1000}, // Output Format 444 [7]=0.
// [6] must be 0!
// Colour Depth for Input Video data [5:4] b11 = 8-bit.
// Input Style [3:2] b10 = Style 1 (ignored when using 444 input).
// DDR Input Edge falling [1]=0 (not using DDR atm).
// Output Colour Space RGB [0]=0.
{8'h17, 8'b01100010}, // Aspect ratio 16:9 [1]=1, 4:3 [1]=0
{8'h18, ypbpr ? 8'h86 : limited[0] ? 8'h8D : limited[1] ? 8'h8E : 8'h00}, // CSC Scaling Factors and Coefficients for RGB Full->Limited.
{8'h19, ypbpr ? 8'hDF : limited[0] ? 8'hBC : 8'hFE}, // Taken from table in ADV7513 Programming Guide.
{8'h1A, ypbpr ? 8'h1A : 8'h00}, // CSC Channel A.
{8'h1B, ypbpr ? 8'h3F : 8'h00},
{8'h1C, ypbpr ? 8'h1E : 8'h00},
{8'h1D, ypbpr ? 8'hE2 : 8'h00},
{8'h1E, ypbpr ? 8'h07 : 8'h01},
{8'h1F, ypbpr ? 8'hE7 : 8'h00},
{8'h20, ypbpr ? 8'h04 : 8'h00}, // CSC Channel B.
{8'h21, ypbpr ? 8'h1C : 8'h00},
{8'h22, ypbpr ? 8'h08 : limited[0] ? 8'h0D : 8'h0E},
{8'h23, ypbpr ? 8'h11 : limited[0] ? 8'hBC : 8'hFE},
{8'h24, ypbpr ? 8'h01 : 8'h00},
{8'h25, ypbpr ? 8'h91 : 8'h00},
{8'h26, ypbpr ? 8'h01 : 8'h01},
{8'h27, 8'h00},
{8'h28, ypbpr ? 8'h1D : 8'h00}, // CSC Channel C.
{8'h29, ypbpr ? 8'hAE : 8'h00},
{8'h2A, ypbpr ? 8'h1B : 8'h00},
{8'h2B, ypbpr ? 8'h73 : 8'h00},
{8'h2C, ypbpr ? 8'h06 : limited[0] ? 8'h0D : 8'h0E},
{8'h2D, ypbpr ? 8'hDF : limited[0] ? 8'hBC : 8'hFE},
{8'h2E, ypbpr ? 8'h07 : 8'h01},
{8'h2F, ypbpr ? 8'hE7 : 8'h00},
{8'h3B, 8'b0000_0000}, // Pixel repetition [6:5] b00 AUTO. [4:3] b00 x1 mult of input clock. [2:1] b00 x1 pixel rep to send to HDMI Rx.
16'h4000, // General Control Packet Enable
{8'h48, 8'b0000_1000}, // [6]=0 Normal bus order!
// [5] DDR Alignment.
// [4:3] b01 Data right justified (for YCbCr 422 input modes).
16'h49A8, // ADI required Write.
16'h4C00, // ADI required Write.
{8'h55, 8'b0001_0000}, // [7] must be 0!. Set RGB444 in AVinfo Frame [6:5], Set active format [4].
// AVI InfoFrame Valid [4].
// Bar Info [3:2] b00 Bars invalid. b01 Bars vertical. b10 Bars horizontal. b11 Bars both.
// Scan Info [1:0] b00 (No data). b01 TV. b10 PC. b11 None.
{8'h57, 1'b0, // [7] IT Content. 0 - No. 1 - Yes (type set in register h59).
3'b000, // [6:4] Color space (ignored for RGB)
(ypbpr | limited) ? 2'b01 : 2'b10, // [3:2] RGB Quantization range
2'b00}, // [1:0] Non-Uniform Scaled: 00 - None. 01 - Horiz. 10 - Vert. 11 - Both.
16'h7301,
{8'h94, 8'b1000_0000}, // [7]=1 HPD Interrupt ENabled.
16'h9902, // ADI required Write.
16'h9B18, // ADI required Write.
16'h9F00, // ADI required Write.
{8'hA1, 8'b0000_0000}, // [6]=1 Monitor Sense Power Down DISabled.
16'hA408, // ADI required Write.
16'hA504, // ADI required Write.
16'hA600, // ADI required Write.
16'hA700, // ADI required Write.
16'hA800, // ADI required Write.
16'hA900, // ADI required Write.
16'hAA00, // ADI required Write.
16'hAB40, // ADI required Write.
{8'hAF, 6'b0000_01,~dvi_mode,1'b0}, // [7]=0 HDCP Disabled.
// [6:5] must be b00!
// [4]=0 Current frame is unencrypted
// [3:2] must be b01!
// [1]=1 HDMI Mode.
// [0] must be b0!
16'hB900, // ADI required Write.
{8'hBA, 8'b0110_0000}, // [7:5] Input Clock delay...
// b000 = -1.2ns.
// b001 = -0.8ns.
// b010 = -0.4ns.
// b011 = No delay.
// b100 = 0.4ns.
// b101 = 0.8ns.
// b110 = 1.2ns.
// b111 = 1.6ns.
16'hBB00, // ADI required Write.
16'hDE9C, // ADI required Write.
16'hE460, // ADI required Write.
16'hFA7D, // Nbr of times to search for good phase
// (Audio stuff on Programming Guide, Page 66)...
{8'h0A, 8'b0000_0000}, // [6:4] Audio Select. b000 = I2S.
// [3:2] Audio Mode. (HBR stuff, leave at 00!).
{8'h0B, 8'b0000_1110}, //
{8'h0C, 8'b0000_0100}, // [7] 0 = Use sampling rate from I2S stream. 1 = Use samp rate from I2C Register.
// [6] 0 = Use Channel Status bits from stream. 1 = Use Channel Status bits from I2C register.
// [2] 1 = I2S0 Enable.
// [1:0] I2S Format: 00 = Standard. 01 = Right Justified. 10 = Left Justified. 11 = AES.
{8'h0D, 8'b0001_0000}, // [4:0] I2S Bit (Word) Width for Right-Justified.
{8'h14, 8'b0000_0010}, // [3:0] Audio Word Length. b0010 = 16 bits.
{8'h15, audio_96k, 7'b010_0000}, // I2S Sampling Rate [7:4]. b0000 = (44.1KHz). b0010 = 48KHz.
// Input ID [3:1] b000 (0) = 24-bit RGB 444 or YCrCb 444 with Separate Syncs.
// Audio Clock Config
16'h0100, //
audio_96k ? 16'h0230 : 16'h0218, // Set N Value 12288/6144
16'h0300, //
16'h0701, //
16'h0822, // Set CTS Value 74250
16'h090A, //
16'hFFFF // END
};
////////////////////////////////////////////////////////////////////
endmodule

View File

@ -55,6 +55,13 @@ module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1,
output reg [15:0] joystick_r_analog_4,
output reg [15:0] joystick_r_analog_5,
input [15:0] joystick_0_rumble, // 15:8 - 'large' rumble motor magnitude, 7:0 'small' rumble motor magnitude
input [15:0] joystick_1_rumble,
input [15:0] joystick_2_rumble,
input [15:0] joystick_3_rumble,
input [15:0] joystick_4_rumble,
input [15:0] joystick_5_rumble,
// paddle 0..255
output reg [7:0] paddle_0,
output reg [7:0] paddle_1,
@ -71,6 +78,29 @@ module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1,
output reg [8:0] spinner_4,
output reg [8:0] spinner_5,
// ps2 keyboard emulation
output ps2_kbd_clk_out,
output ps2_kbd_data_out,
input ps2_kbd_clk_in,
input ps2_kbd_data_in,
input [2:0] ps2_kbd_led_status,
input [2:0] ps2_kbd_led_use,
output ps2_mouse_clk_out,
output ps2_mouse_data_out,
input ps2_mouse_clk_in,
input ps2_mouse_data_in,
// ps2 alternative interface.
// [8] - extended, [9] - pressed, [10] - toggles with every press/release
output reg [10:0] ps2_key = 0,
// [24] - toggles with every event
output reg [24:0] ps2_mouse = 0,
output reg [15:0] ps2_mouse_ext = 0, // 15:8 - reserved(additional buttons), 7:0 - wheel movements
output [1:0] buttons,
output forced_scandoubler,
output direct_video,
@ -79,10 +109,12 @@ module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1,
//toggle to force notify of video mode change
input new_vmode,
output reg [63:0] status,
input [63:0] status_in,
input status_set,
input [15:0] status_menumask,
inout [21:0] gamma_bus,
output reg [127:0] status,
input [127:0] status_in,
input status_set,
input [15:0] status_menumask,
input info_req,
input [7:0] info,
@ -133,31 +165,6 @@ module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1,
output reg [7:0] uart_mode,
output reg [31:0] uart_speed,
// ps2 keyboard emulation
output ps2_kbd_clk_out,
output ps2_kbd_data_out,
input ps2_kbd_clk_in,
input ps2_kbd_data_in,
input [2:0] ps2_kbd_led_status,
input [2:0] ps2_kbd_led_use,
output ps2_mouse_clk_out,
output ps2_mouse_data_out,
input ps2_mouse_clk_in,
input ps2_mouse_data_in,
// ps2 alternative interface.
// [8] - extended, [9] - pressed, [10] - toggles with every press/release
output reg [10:0] ps2_key = 0,
// [24] - toggles with every event
output reg [24:0] ps2_mouse = 0,
output reg [15:0] ps2_mouse_ext = 0, // 15:8 - reserved(additional buttons), 7:0 - wheel movements
inout [21:0] gamma_bus,
// for core-specific extensions
inout [35:0] EXT_BUS
);
@ -259,7 +266,7 @@ always@(posedge clk_sys) begin : uio_block
reg [3:0] pdsp_idx;
reg ps2skip = 0;
reg [3:0] stflg = 0;
reg [63:0] status_req;
reg[127:0] status_req;
reg old_status_set = 0;
reg old_upload_req = 0;
reg upload_req = 0;
@ -330,6 +337,12 @@ always@(posedge clk_sys) begin : uio_block
'h39: io_dout <= 1;
'h3C: if(upload_req) begin io_dout <= {ioctl_upload_index, 8'd1}; upload_req <= 0; end
'h3E: io_dout <= 1; // shadow mask
'h003F: io_dout <= joystick_0_rumble;
'h013F: io_dout <= joystick_1_rumble;
'h023F: io_dout <= joystick_2_rumble;
'h033F: io_dout <= joystick_3_rumble;
'h043F: io_dout <= joystick_4_rumble;
'h053F: io_dout <= joystick_5_rumble;
endcase
sd_buff_addr <= 0;
@ -455,13 +468,17 @@ always@(posedge clk_sys) begin : uio_block
// send image info
'h1d: if(byte_cnt<5) img_size[{byte_cnt-1'b1, 4'b0000} +:16] <= io_din;
// status, 64bit version
'h1e: if(!byte_cnt[MAX_W:3]) begin
case(byte_cnt[2:0])
1: status[15:00] <= io_din;
2: status[31:16] <= io_din;
3: status[47:32] <= io_din;
4: status[63:48] <= io_din;
// status, 128bit version
'h1e: if(!byte_cnt[MAX_W:4]) begin
case(byte_cnt[3:0])
1: status[15:00] <= io_din;
2: status[31:16] <= io_din;
3: status[47:32] <= io_din;
4: status[63:48] <= io_din;
5: status[79:64] <= io_din;
6: status[95:80] <= io_din;
7: status[111:96] <= io_din;
8: status[127:112] <= io_din;
endcase
end
@ -491,12 +508,16 @@ always@(posedge clk_sys) begin : uio_block
'h24: TIMESTAMP[(byte_cnt-6'd1)<<4 +:16] <= io_din;
//status set
'h29: if(!byte_cnt[MAX_W:3]) begin
case(byte_cnt[2:0])
'h29: if(!byte_cnt[MAX_W:4]) begin
case(byte_cnt[3:0])
1: io_dout <= status_req[15:00];
2: io_dout <= status_req[31:16];
3: io_dout <= status_req[47:32];
4: io_dout <= status_req[63:48];
5: io_dout <= status_req[79:64];
6: io_dout <= status_req[95:80];
7: io_dout <= status_req[111:96];
8: io_dout <= status_req[127:112];
endcase
end
@ -870,22 +891,28 @@ always @(posedge clk_sys) begin
11: dout <= vid_pix[31:16];
12: dout <= vid_vtime_hdmi[15:0];
13: dout <= vid_vtime_hdmi[31:16];
14: dout <= vid_ccnt[15:0];
15: dout <= vid_ccnt[31:16];
default dout <= 0;
endcase
end
reg [31:0] vid_hcnt = 0;
reg [31:0] vid_vcnt = 0;
reg [31:0] vid_ccnt = 0;
reg [7:0] vid_nres = 0;
reg [1:0] vid_int = 0;
always @(posedge clk_vid) begin
integer hcnt;
integer vcnt;
integer ccnt;
reg old_vs= 0, old_de = 0, old_vmode = 0;
reg [3:0] resto = 0;
reg calch = 0;
if(calch & de) ccnt <= ccnt + 1;
if(ce_pix) begin
old_vs <= vs;
old_de <= de;
@ -906,9 +933,11 @@ always @(posedge clk_vid) begin
if(&resto) vid_nres <= vid_nres + 1'd1;
vid_hcnt <= hcnt;
vid_vcnt <= vcnt;
vid_ccnt <= ccnt;
end
vcnt <= 0;
hcnt <= 0;
ccnt <= 0;
calch <= 1;
end
end

View File

@ -102,19 +102,19 @@ end
endmodule
module ltc2308_tape #(parameter HIST_LOW = 16, HIST_HIGH = 64, ADC_RATE = 48000, CLK_RATE = 50000000)
module ltc2308_tape #(parameter HIST_LOW = 16, HIST_HIGH = 64, ADC_RATE = 48000, CLK_RATE = 50000000, NUM_CH = 1)
(
input reset,
input clk,
input reset,
input clk,
inout [3:0] ADC_BUS,
output reg dout,
output active
inout [3:0] ADC_BUS,
output reg dout,
output active,
output adc_sync,
output [(NUM_CH*12)-1:0] adc_data
);
wire [11:0] adc_data;
wire adc_sync;
ltc2308 #(1, ADC_RATE, CLK_RATE) adc
ltc2308 #(NUM_CH, ADC_RATE, CLK_RATE) adc
(
.reset(reset),
.clk(clk),
@ -133,8 +133,8 @@ always @(posedge clk) begin
data1 <= data2;
data2 <= data3;
data3 <= data4;
data4 <= adc_data;
data4 <= adc_data[11:0];
sum <= data1+data2+data3+data4;
if(sum[13:2]<HIST_LOW) dout <= 0;
@ -148,7 +148,7 @@ reg [1:0] act;
always @(posedge clk) begin
reg [31:0] onesec;
reg old_dout;
onesec <= onesec + 1;
if(onesec>CLK_RATE) begin
onesec <= 0;

View File

@ -131,7 +131,7 @@ wire [21:0] osd_h_hdr = (info || rot) ? osd_h : (osd_h + OSD_HDR);
// pipeline the comparisons a bit
always @(posedge clk_video) if(ce_pix) begin
v_cnt_h <= v_cnt < osd_t;
v_cnt_h <= v_cnt <= osd_t;
v_cnt_1 <= v_cnt < 320;
v_cnt_2 <= v_cnt < 640;
v_cnt_3 <= v_cnt < 960;

View File

@ -16,6 +16,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) v
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_video.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) vga_out.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) yc_out.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2c.v ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) alsa.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2s.v ]
@ -25,7 +26,6 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ltc2308.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sigma_delta_dac.v ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) mt32pi.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hdmi_config.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) mcp23009.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) f2sdram_safe_terminator.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ddr_svc.sv ]

View File

@ -45,6 +45,7 @@ set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM2_
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM2_*
set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM2_DQ[*]
set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM2_DQ[*]
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SDRAM2_DQ[*]
set_instance_assignment -name ALLOW_SYNCH_CTRL_USAGE OFF -to *|SDRAM2_*
set_global_assignment -name VERILOG_MACRO "MISTER_DUAL_SDRAM=1"

View File

@ -28,11 +28,12 @@ set_false_path -to [get_ports {VGA_*}]
set_false_path -to [get_ports {AUDIO_SPDIF}]
set_false_path -to [get_ports {AUDIO_L}]
set_false_path -to [get_ports {AUDIO_R}]
set_false_path -from {get_ports {SW[*]}}
set_false_path -to {cfg[*]}
set_false_path -from {cfg[*]}
set_false_path -from {VSET[*]}
set_false_path -to {wcalc[*] hcalc[*]}
set_false_path -to {hdmi_width[*] hdmi_height[*]}
set_false_path -to {hdmi_width[*] hdmi_height[*]}
set_multicycle_path -to {*_osd|osd_vcnt*} -setup 2
set_multicycle_path -to {*_osd|osd_vcnt*} -hold 1
@ -55,6 +56,7 @@ set_false_path -from {FB_BASE[*] FB_BASE[*] FB_WIDTH[*] FB_HEIGHT[*] LFB_HMIN[*]
set_false_path -to {vol_att[*] scaler_flt[*] led_overtake[*] led_state[*]}
set_false_path -from {vol_att[*] scaler_flt[*] led_overtake[*] led_state[*]}
set_false_path -from {aflt_* acx* acy* areset* arc*}
set_false_path -from {arx* ary*}
set_false_path -from {vs_line*}
set_false_path -from {ascal|o_ihsize*}
@ -62,7 +64,7 @@ set_false_path -from {ascal|o_ivsize*}
set_false_path -from {ascal|o_format*}
set_false_path -from {ascal|o_hdown}
set_false_path -from {ascal|o_vdown}
set_false_path -from {ascal|o_hmin* ascal|o_hmax* ascal|o_vmin* ascal|o_vmax*}
set_false_path -from {ascal|o_hmin* ascal|o_hmax* ascal|o_vmin* ascal|o_vmax* ascal|o_vrrmax* ascal|o_vrr}
set_false_path -from {ascal|o_hdisp* ascal|o_vdisp*}
set_false_path -from {ascal|o_htotal* ascal|o_vtotal*}
set_false_path -from {ascal|o_hsstart* ascal|o_vsstart* ascal|o_hsend* ascal|o_vsend*}

View File

@ -168,7 +168,7 @@ assign LED = (led_overtake & led_state) | (~led_overtake & {1'b0,led_locked,1'b0
wire btn_r, btn_o, btn_u;
`ifdef MISTER_DUAL_SDRAM
assign {btn_r,btn_o,btn_u} = {mcp_btn[1],mcp_btn[2],mcp_btn[0]};
assign {btn_r,btn_o,btn_u} = SW[3] ? {mcp_btn[1],mcp_btn[2],mcp_btn[0]} : ~{SDRAM2_DQ[9],SDRAM2_DQ[13],SDRAM2_DQ[11]};
`else
assign {btn_r,btn_o,btn_u} = ~{BTN_RESET,BTN_OSD,BTN_USER} | {mcp_btn[1],mcp_btn[2],mcp_btn[0]};
`endif
@ -212,13 +212,13 @@ end
// gp_in[31] = 0 - quick flag that FPGA is initialized (HPS reads 1 when FPGA is not in user mode)
// used to avoid lockups while JTAG loading
wire [31:0] gp_in = {1'b0, btn_user | btn[1], btn_osd | btn[0], SW[3], 8'd0, io_ver, io_ack, io_wide, io_dout};
wire [31:0] gp_in = {1'b0, btn_user | btn[1], btn_osd | btn[0], SW[3], 8'd0, io_ver, io_ack, io_wide, io_dout | io_dout_sys};
wire [31:0] gp_out;
wire [1:0] io_ver = 1; // 0 - obsolete. 1 - optimized HPS I/O. 2,3 - reserved for future.
wire io_wait;
wire io_wide;
wire [15:0] io_dout;
wire [15:0] io_dout;
wire [15:0] io_din = gp_outr[15:0];
wire io_clk = gp_outr[17];
wire io_ss0 = gp_outr[18];
@ -270,7 +270,6 @@ reg [15:0] cfg;
reg cfg_set = 0;
wire vga_fb = cfg[12] | vga_force_scaler;
wire [1:0] hdmi_limited = {cfg[11],cfg[8]};
`ifdef MISTER_DEBUG_NOHDMI
wire direct_video = 1;
@ -278,12 +277,11 @@ wire direct_video = 1;
wire direct_video = cfg[10];
`endif
wire dvi_mode = cfg[7];
wire audio_96k = cfg[6];
wire csync_en = cfg[3];
wire ypbpr_en = cfg[5];
wire io_osd_vga = io_ss1 & ~io_ss2;
`ifndef MISTER_DUAL_SDRAM
wire ypbpr_en = cfg[5];
wire sog = cfg[9];
wire vga_scaler = cfg[2] | vga_force_scaler;
`endif
@ -304,12 +302,13 @@ reg [11:0] VSET = 0, HSET = 0;
reg FREESCALE = 0;
reg [2:0] scaler_flt;
reg lowlat = 0;
reg cfg_dis = 0;
reg cfg_done = 0;
reg vs_wait = 0;
reg [11:0] vs_line = 0;
reg scaler_out = 0;
reg vrr_mode = 0;
reg [31:0] aflt_rate = 7056000;
reg [39:0] acx = 4258969;
@ -324,16 +323,16 @@ reg [12:0] arc1x = 0;
reg [12:0] arc1y = 0;
reg [12:0] arc2x = 0;
reg [12:0] arc2y = 0;
reg [15:0] io_dout_sys;
always@(posedge clk_sys) begin
reg [7:0] cmd;
reg has_cmd;
reg old_strobe;
reg [7:0] cnt = 0;
reg vs_d0,vs_d1,vs_d2;
reg [4:0] acx_att;
reg [7:0] fb_crc;
old_strobe <= io_strobe;
coef_wr <= 0;
`ifndef MISTER_DEBUG_NOHDMI
@ -346,9 +345,11 @@ always@(posedge clk_sys) begin
areset <= 0;
acx_att <= 0;
acx <= acx >> acx_att;
io_dout_sys <= 0;
end
else
if(~old_strobe & io_strobe) begin
if(io_strobe) begin
io_dout_sys <= 0;
if(!has_cmd) begin
has_cmd <= 1;
cmd <= io_din[7:0];
@ -365,6 +366,10 @@ always@(posedge clk_sys) begin
acy2 <= -24'd2023767;
areset <= 1;
end
if(io_din[7:0] == 'h20) io_dout_sys <= 'b11;
`ifndef MISTER_DEBUG_NOHDMI
if(io_din[7:0] == 'h40) io_dout_sys <= fb_crc;
`endif
end
else begin
cnt <= cnt + 1'd1;
@ -377,14 +382,14 @@ always@(posedge clk_sys) begin
cfg_set <= 0;
if(cnt<8) begin
case(cnt[2:0])
0: WIDTH <= io_din[11:0];
1: HFP <= io_din[11:0];
2: HS <= {io_din[15], io_din[11:0]};
3: HBP <= io_din[11:0];
4: HEIGHT <= io_din[11:0];
5: VFP <= io_din[11:0];
6: VS <= {io_din[15],io_din[11:0]};
7: VBP <= io_din[11:0];
0: {HDMI_PR,vrr_mode,WIDTH} <= {io_din[15:14], io_din[11:0]};
1: HFP <= io_din[11:0];
2: HS <= {io_din[15], io_din[11:0]};
3: HBP <= io_din[11:0];
4: HEIGHT <= io_din[11:0];
5: VFP <= io_din[11:0];
6: VS <= {io_din[15],io_din[11:0]};
7: VBP <= io_din[11:0];
endcase
`ifndef MISTER_DEBUG_NOHDMI
if(cnt == 1) begin
@ -401,7 +406,7 @@ always@(posedge clk_sys) begin
cfg_custom_t <= ~cfg_custom_t;
cnt[2:0] <= 3'b100;
end
if(cnt == 8) {lowlat,cfg_dis} <= io_din[15:14];
if(cnt == 8) {lowlat,cfg_done} <= {io_din[15],1'b1};
`endif
end
end
@ -458,10 +463,42 @@ always@(posedge clk_sys) begin
end
`ifndef MISTER_DEBUG_NOHDMI
if(cmd == 'h3E) {shadowmask_wr,shadowmask_data} <= {1'b1, io_din};
if(cmd == 'h40) begin
case(cnt[3:0])
0: io_dout_sys <= {arxy, arx};
1: io_dout_sys <= {arxy, ary};
2: io_dout_sys <= {LFB_EN, FB_EN, FB_FMT};
3: io_dout_sys <= FB_WIDTH;
4: io_dout_sys <= FB_HEIGHT;
5: io_dout_sys <= FB_BASE[15:0];
6: io_dout_sys <= FB_BASE[31:16];
7: io_dout_sys <= FB_STRIDE;
endcase
end
`endif
`ifndef MISTER_DISABLE_YC
if(cmd == 'h41) begin
case(cnt[3:0])
0: {pal_en,cvbs,yc_en} <= io_din[2:0];
1: PhaseInc[15:0] <= io_din;
2: PhaseInc[31:16] <= io_din;
3: PhaseInc[39:32] <= io_din[7:0];
4: ColorBurst_Range[15:0] <= io_din;
5: ColorBurst_Range[16] <= io_din[0];
endcase
end
`endif
end
end
`ifndef MISTER_DEBUG_NOHDMI
fb_crc <= {LFB_EN, FB_EN, FB_FMT}
^ FB_WIDTH[7:0] ^ FB_WIDTH[11:8]
^ FB_HEIGHT[7:0] ^ FB_HEIGHT[11:8]
^ arx[7:0] ^ arx[11:8] ^ arxy
^ ary[7:0] ^ ary[11:8];
`endif
vs_d0 <= HDMI_TX_VS;
if(vs_d0 == HDMI_TX_VS) vs_d1 <= vs_d0;
@ -482,17 +519,6 @@ cyclonev_hps_interface_peripheral_uart uart
.txd(uart_txd)
);
wire aspi_sck,aspi_mosi,aspi_ss,aspi_miso;
cyclonev_hps_interface_peripheral_spi_master spi
(
.sclk_out(aspi_sck),
.txd(aspi_mosi), // mosi
.rxd(aspi_miso), // miso
.ss_0_n(aspi_ss),
.ss_in_n(1)
);
wire [63:0] f2h_irq = {video_sync,HDMI_TX_VS};
cyclonev_hps_interface_interrupts interrupts
(
@ -598,11 +624,13 @@ ddr_svc ddr_svc
.ram_write(ram2_write),
.ram_bcnt(ram2_bcnt),
`ifndef MISTER_DISABLE_ALSA
.ch0_addr(alsa_address),
.ch0_burst(1),
.ch0_data(alsa_readdata),
.ch0_req(alsa_req),
.ch0_ready(alsa_ready),
`endif
.ch1_addr(pal_addr),
.ch1_burst(128),
@ -634,6 +662,11 @@ wire clk_hdmi = hdmi_clk_out;
ascal
#(
.RAMBASE(32'h20000000),
`ifdef MISTER_SMALL_VBUF
.RAMSIZE(32'h00200000),
`else
.RAMSIZE(32'h00800000),
`endif
`ifndef MISTER_FB
.PALETTE2("false"),
`else
@ -695,6 +728,8 @@ ascal
.vdisp (HEIGHT),
.vmin (vmin),
.vmax (vmax),
.vrr (vrr_mode),
.vrrmax (HEIGHT + VBP + VS[11:0] + 12'd1),
.mode ({~lowlat,LFB_EN ? LFB_FLT : |scaler_flt,2'b00}),
.poly_clk (clk_sys),
@ -804,37 +839,40 @@ reg [11:0] vmax;
reg [11:0] hdmi_height;
reg [11:0] hdmi_width;
reg [11:0] arx;
reg [11:0] ary;
reg arxy;
always @(posedge clk_vid) begin
reg [11:0] hmini,hmaxi,vmini,vmaxi;
reg [11:0] wcalc,videow,arx;
reg [11:0] hcalc,videoh,ary;
reg [11:0] wcalc,videow;
reg [11:0] hcalc,videoh;
reg [2:0] state;
reg xy;
hdmi_height <= (VSET && (VSET < HEIGHT)) ? VSET : HEIGHT;
hdmi_width <= (HSET && (HSET < WIDTH)) ? HSET : WIDTH;
hdmi_width <= (HSET && (HSET < WIDTH)) ? HSET << HDMI_PR : WIDTH << HDMI_PR;
if(!ARY) begin
if(ARX == 1) begin
arx <= arc1x[11:0];
ary <= arc1y[11:0];
xy <= arc1x[12] | arc1y[12];
arx <= arc1x[11:0];
ary <= arc1y[11:0];
arxy <= arc1x[12] | arc1y[12];
end
else if(ARX == 2) begin
arx <= arc2x[11:0];
ary <= arc2y[11:0];
xy <= arc2x[12] | arc2y[12];
arx <= arc2x[11:0];
ary <= arc2y[11:0];
arxy <= arc2x[12] | arc2y[12];
end
else begin
arx <= 0;
ary <= 0;
xy <= 0;
arx <= 0;
ary <= 0;
arxy <= 0;
end
end
else begin
arx <= ARX[11:0];
ary <= ARY[11:0];
xy <= ARX[12] | ARY[12];
arx <= ARX[11:0];
ary <= ARY[11:0];
arxy <= ARX[12] | ARY[12];
end
ar_md_start <= 0;
@ -852,7 +890,7 @@ always @(posedge clk_vid) begin
hcalc <= hdmi_height;
state <= 6;
end
else if(xy) begin
else if(arxy) begin
wcalc <= arx;
hcalc <= ary;
state <= 6;
@ -881,7 +919,7 @@ always @(posedge clk_vid) begin
end
6: begin
videow <= (wcalc > hdmi_width) ? hdmi_width : wcalc[11:0];
videow <= (wcalc > hdmi_width) ? (hdmi_width >> HDMI_PR) : (wcalc[11:0] >> HDMI_PR);
videoh <= (hcalc > hdmi_height) ? hdmi_height : hcalc[11:0];
end
@ -907,7 +945,7 @@ pll_hdmi_adj pll_hdmi_adj
.reset_na(~reset_req),
.llena(lowlat),
.lltune({16{hdmi_config_done | cfg_dis}} & lltune),
.lltune({16{cfg_done}} & lltune),
.locked(led_locked),
.i_waitrequest(adj_waitrequest),
.i_write(adj_write),
@ -955,14 +993,15 @@ pll_hdmi pll_hdmi
`endif
//1920x1080@60 PCLK=148.5MHz CEA
reg [11:0] WIDTH = 1920;
reg [11:0] HFP = 88;
reg [12:0] HS = 48;
reg [11:0] HBP = 148;
reg [11:0] HEIGHT = 1080;
reg [11:0] VFP = 4;
reg [12:0] VS = 5;
reg [11:0] VBP = 36;
reg [11:0] WIDTH = 1920;
reg [11:0] HFP = 88;
reg [12:0] HS = 48;
reg [11:0] HBP = 148;
reg [11:0] HEIGHT = 1080;
reg [11:0] VFP = 4;
reg [12:0] VS = 5;
reg [11:0] VBP = 36;
reg HDMI_PR = 0;
wire [63:0] reconfig_to_pll;
wire [63:0] reconfig_from_pll;
@ -1035,22 +1074,6 @@ wire cfg_ready = 1;
`endif
wire hdmi_config_done;
hdmi_config hdmi_config
(
.iCLK(FPGA_CLK1_50),
.iRST_N(cfg_ready & ~HDMI_TX_INT & ~cfg_dis),
.done(hdmi_config_done),
.I2C_SCL(HDMI_I2C_SCL),
.I2C_SDA(HDMI_I2C_SDA),
.dvi_mode(dvi_mode),
.audio_96k(audio_96k),
.limited(hdmi_limited),
.ypbpr(ypbpr_en & direct_video)
);
assign HDMI_I2C_SCL = hdmi_scl_en ? 1'b0 : 1'bZ;
assign HDMI_I2C_SDA = hdmi_sda_en ? 1'b0 : 1'bZ;
@ -1132,34 +1155,41 @@ csync csync_hdmi(clk_hdmi, hdmi_hs_osd, hdmi_vs_osd, hdmi_cs_osd);
reg [23:0] dv_data;
reg dv_hs, dv_vs, dv_de;
wire [23:0] dv_data_osd;
wire dv_hs_osd, dv_vs_osd, dv_cs_osd;
always @(posedge clk_vid) begin
reg [23:0] dv_d1, dv_d2;
reg dv_de1, dv_de2, dv_hs1, dv_hs2, dv_vs1, dv_vs2;
reg [12:0] vsz, vcnt;
reg [12:0] vsz, vcnt, vcnt_l, vcnt_ll;
reg old_hs, old_vs;
reg vde;
reg [3:0] hss;
if(ce_pix) begin
hss <= (hss << 1) | vga_hs_osd;
hss <= (hss << 1) | dv_hs_osd;
old_hs <= vga_hs_osd;
if(~old_hs && vga_hs_osd) begin
old_vs <= vga_vs_osd;
old_hs <= dv_hs_osd;
if(~old_hs && dv_hs_osd) begin
old_vs <= dv_vs_osd;
if(~&vcnt) vcnt <= vcnt + 1'd1;
if(~old_vs & vga_vs_osd & ~f1) vsz <= vcnt;
if(old_vs & ~vga_vs_osd) vcnt <= 0;
if(~old_vs & dv_vs_osd) begin
if (vcnt != vcnt_ll || vcnt < vcnt_l) vsz <= vcnt;
vcnt_l <= vcnt;
vcnt_ll <= vcnt_l;
end
if(old_vs & ~dv_vs_osd) vcnt <= 0;
if(vcnt == 1) vde <= 1;
if(vcnt == vsz - 3) vde <= 0;
end
dv_de1 <= !{hss,vga_hs_osd} && vde;
dv_hs1 <= csync_en ? vga_cs_osd : vga_hs_osd;
dv_vs1 <= vga_vs_osd;
dv_de1 <= !{hss,dv_hs_osd} && vde;
dv_hs1 <= csync_en ? dv_cs_osd : dv_hs_osd;
dv_vs1 <= dv_vs_osd;
end
dv_d1 <= vga_data_osd;
dv_d1 <= dv_data_osd;
dv_d2 <= dv_d1;
dv_de2 <= dv_de1;
dv_hs2 <= dv_hs1;
@ -1171,6 +1201,12 @@ always @(posedge clk_vid) begin
dv_vs <= dv_vs2;
end
`ifndef MISTER_DISABLE_YC
assign {dv_data_osd, dv_hs_osd, dv_vs_osd, dv_cs_osd } = ~yc_en ? {vga_data_osd, vga_hs_osd, vga_vs_osd, vga_cs_osd } : {yc_o, yc_hs, yc_vs, yc_cs };
`else
assign {dv_data_osd, dv_hs_osd, dv_vs_osd, dv_cs_osd } = {vga_data_osd, vga_hs_osd, vga_vs_osd, vga_cs_osd };
`endif
wire hdmi_tx_clk;
`ifndef MISTER_DEBUG_NOHDMI
cyclonev_clkselect hdmi_clk_sw
@ -1289,6 +1325,7 @@ wire vga_cs_osd;
csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd);
`ifndef MISTER_DUAL_SDRAM
wire VGA_DISABLE;
wire [23:0] vgas_o;
wire vgas_hs, vgas_vs, vgas_cs;
vga_out vga_scaler_out
@ -1305,8 +1342,8 @@ csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd);
.csync_o(vgas_cs)
);
wire [23:0] vga_o;
wire vga_hs, vga_vs, vga_cs;
wire [23:0] vga_o, vga_o_t;
wire vga_hs, vga_vs, vga_cs, vga_hs_t, vga_vs_t, vga_cs_t;
vga_out vga_out
(
.clk(clk_vid),
@ -1314,20 +1351,51 @@ csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd);
.hsync(vga_hs_osd),
.vsync(vga_vs_osd),
.csync(vga_cs_osd),
.dout(vga_o),
.dout(vga_o_t),
.din(vga_data_osd),
.hsync_o(vga_hs),
.vsync_o(vga_vs),
.csync_o(vga_cs)
.hsync_o(vga_hs_t),
.vsync_o(vga_vs_t),
.csync_o(vga_cs_t)
);
`ifndef MISTER_DISABLE_YC
reg pal_en;
reg yc_en;
reg cvbs;
reg [16:0] ColorBurst_Range;
reg [39:0] PhaseInc;
wire [23:0] yc_o;
wire yc_hs, yc_vs, yc_cs;
yc_out yc_out
(
.clk(clk_vid),
.PAL_EN(pal_en),
.CVBS(cvbs),
.PHASE_INC(PhaseInc),
.COLORBURST_RANGE(ColorBurst_Range),
.hsync(vga_hs_osd),
.vsync(vga_vs_osd),
.csync(vga_cs_osd),
.dout(yc_o),
.din(vga_data_osd),
.hsync_o(yc_hs),
.vsync_o(yc_vs),
.csync_o(yc_cs)
);
assign {vga_o, vga_hs, vga_vs, vga_cs } = ~yc_en ? {vga_o_t, vga_hs_t, vga_vs_t, vga_cs_t } : {yc_o, yc_hs, yc_vs, yc_cs };
`else
assign {vga_o, vga_hs, vga_vs, vga_cs } = {vga_o_t, vga_hs_t, vga_vs_t, vga_cs_t } ;
`endif
wire cs1 = (vga_fb | vga_scaler) ? vgas_cs : vga_cs;
assign VGA_VS = (VGA_EN | SW[3]) ? 1'bZ :((((vga_fb | vga_scaler) ? ~vgas_vs : ~vga_vs) | csync_en) ^ VS[12]);
assign VGA_HS = (VGA_EN | SW[3]) ? 1'bZ : (((vga_fb | vga_scaler) ? (csync_en ? ~vgas_cs : ~vgas_hs) : (csync_en ? ~vga_cs : ~vga_hs)) ^ HS[12]);
assign VGA_R = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[23:18] : vga_o[23:18];
assign VGA_G = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[15:10] : vga_o[15:10];
assign VGA_B = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[7:2] : vga_o[7:2] ;
assign VGA_VS = (VGA_EN | SW[3]) ? 1'bZ : (((vga_fb | vga_scaler) ? (~vgas_vs ^ VS[12]) : VGA_DISABLE ? 1'd1 : ~vga_vs) | csync_en);
assign VGA_HS = (VGA_EN | SW[3]) ? 1'bZ : ((vga_fb | vga_scaler) ? ((csync_en ? ~vgas_cs : ~vgas_hs) ^ HS[12]) : VGA_DISABLE ? 1'd1 : (csync_en ? ~vga_cs : ~vga_hs));
assign VGA_R = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[23:18] : VGA_DISABLE ? 6'd0 : vga_o[23:18];
assign VGA_G = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[15:10] : VGA_DISABLE ? 6'd0 : vga_o[15:10];
assign VGA_B = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[7:2] : VGA_DISABLE ? 6'd0 : vga_o[7:2] ;
`endif
reg video_sync = 0;
@ -1400,8 +1468,10 @@ audio_out audio_out
.core_l(audio_l),
.core_r(audio_r),
`ifndef MISTER_DISABLE_ALSA
.alsa_l(alsa_l),
.alsa_r(alsa_r),
`endif
.i2s_bclk(HDMI_SCLK),
.i2s_lrclk(HDMI_LRCLK),
@ -1414,6 +1484,18 @@ audio_out audio_out
);
`ifndef MISTER_DISABLE_ALSA
wire aspi_sck,aspi_mosi,aspi_ss,aspi_miso;
cyclonev_hps_interface_peripheral_spi_master spi
(
.sclk_out(aspi_sck),
.txd(aspi_mosi), // mosi
.rxd(aspi_miso), // miso
.ss_0_n(aspi_ss),
.ss_in_n(1)
);
wire [28:0] alsa_address;
wire [63:0] alsa_readdata;
wire alsa_ready;
@ -1440,6 +1522,7 @@ alsa alsa
.pcm_l(alsa_l),
.pcm_r(alsa_r)
);
`endif
//////////////// User I/O (USB 3.0 connector) /////////////////////////
@ -1560,6 +1643,10 @@ emu emu
.VGA_F1(f1),
.VGA_SCALER(vga_force_scaler),
`ifndef MISTER_DUAL_SDRAM
.VGA_DISABLE(VGA_DISABLE),
`endif
.HDMI_WIDTH(direct_video ? 12'd0 : hdmi_width),
.HDMI_HEIGHT(direct_video ? 12'd0 : hdmi_height),
.HDMI_FREEZE(freeze),

230
sys/yc_out.sv Normal file
View File

@ -0,0 +1,230 @@
//============================================================================
// YC - Luma / Chroma Generation
// Copyright (C) 2022 Mike Simone
//
// 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.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//============================================================================
/*
Colorspace
Y 0.299R' + 0.587G' + 0.114B'
U 0.492(B' - Y) = 504 (X 1024)
V 0.877(R' - Y) = 898 (X 1024)
*/
//////////////////////////////////////////////////////////
module yc_out
(
input clk,
input [39:0] PHASE_INC,
input PAL_EN,
input CVBS,
input [16:0] COLORBURST_RANGE,
input hsync,
input vsync,
input csync,
input [23:0] din,
output [23:0] dout,
output reg hsync_o,
output reg vsync_o,
output reg csync_o
);
wire [7:0] red = din[23:16];
wire [7:0] green = din[15:8];
wire [7:0] blue = din[7:0];
logic [9:0] red_1, blue_1, green_1, red_2, blue_2, green_2;
logic signed [20:0] yr = 0, yb = 0, yg = 0;
typedef struct {
logic signed [20:0] y;
logic signed [20:0] c;
logic signed [20:0] u;
logic signed [20:0] v;
logic hsync;
logic vsync;
logic csync;
} phase_t;
localparam MAX_PHASES = 7'd8;
phase_t phase[MAX_PHASES];
reg unsigned [7:0] Y, C, c, U, V;
reg [10:0] cburst_phase; // colorburst counter
reg unsigned [7:0] vref = 'd128; // Voltage reference point (Used for Chroma)
logic [7:0] chroma_LUT_COS; // Chroma cos LUT reference
logic [7:0] chroma_LUT_SIN; // Chroma sin LUT reference
logic [7:0] chroma_LUT_BURST; // Chroma colorburst LUT reference
logic [7:0] chroma_LUT = 8'd0;
/*
THe following LUT table was calculated by Sin(2*pi*t/2^8) where t: 0 - 255
*/
/*************************************
8 bit Sine look up Table
**************************************/
wire signed [10:0] chroma_SIN_LUT[256] = '{
11'h000, 11'h006, 11'h00C, 11'h012, 11'h018, 11'h01F, 11'h025, 11'h02B, 11'h031, 11'h037, 11'h03D, 11'h044, 11'h04A, 11'h04F,
11'h055, 11'h05B, 11'h061, 11'h067, 11'h06D, 11'h072, 11'h078, 11'h07D, 11'h083, 11'h088, 11'h08D, 11'h092, 11'h097, 11'h09C,
11'h0A1, 11'h0A6, 11'h0AB, 11'h0AF, 11'h0B4, 11'h0B8, 11'h0BC, 11'h0C1, 11'h0C5, 11'h0C9, 11'h0CC, 11'h0D0, 11'h0D4, 11'h0D7,
11'h0DA, 11'h0DD, 11'h0E0, 11'h0E3, 11'h0E6, 11'h0E9, 11'h0EB, 11'h0ED, 11'h0F0, 11'h0F2, 11'h0F4, 11'h0F5, 11'h0F7, 11'h0F8,
11'h0FA, 11'h0FB, 11'h0FC, 11'h0FD, 11'h0FD, 11'h0FE, 11'h0FE, 11'h0FE, 11'h0FF, 11'h0FE, 11'h0FE, 11'h0FE, 11'h0FD, 11'h0FD,
11'h0FC, 11'h0FB, 11'h0FA, 11'h0F8, 11'h0F7, 11'h0F5, 11'h0F4, 11'h0F2, 11'h0F0, 11'h0ED, 11'h0EB, 11'h0E9, 11'h0E6, 11'h0E3,
11'h0E0, 11'h0DD, 11'h0DA, 11'h0D7, 11'h0D4, 11'h0D0, 11'h0CC, 11'h0C9, 11'h0C5, 11'h0C1, 11'h0BC, 11'h0B8, 11'h0B4, 11'h0AF,
11'h0AB, 11'h0A6, 11'h0A1, 11'h09C, 11'h097, 11'h092, 11'h08D, 11'h088, 11'h083, 11'h07D, 11'h078, 11'h072, 11'h06D, 11'h067,
11'h061, 11'h05B, 11'h055, 11'h04F, 11'h04A, 11'h044, 11'h03D, 11'h037, 11'h031, 11'h02B, 11'h025, 11'h01F, 11'h018, 11'h012,
11'h00C, 11'h006, 11'h000, 11'h7F9, 11'h7F3, 11'h7ED, 11'h7E7, 11'h7E0, 11'h7DA, 11'h7D4, 11'h7CE, 11'h7C8, 11'h7C2, 11'h7BB,
11'h7B5, 11'h7B0, 11'h7AA, 11'h7A4, 11'h79E, 11'h798, 11'h792, 11'h78D, 11'h787, 11'h782, 11'h77C, 11'h777, 11'h772, 11'h76D,
11'h768, 11'h763, 11'h75E, 11'h759, 11'h754, 11'h750, 11'h74B, 11'h747, 11'h743, 11'h73E, 11'h73A, 11'h736, 11'h733, 11'h72F,
11'h72B, 11'h728, 11'h725, 11'h722, 11'h71F, 11'h71C, 11'h719, 11'h716, 11'h714, 11'h712, 11'h70F, 11'h70D, 11'h70B, 11'h70A,
11'h708, 11'h707, 11'h705, 11'h704, 11'h703, 11'h702, 11'h702, 11'h701, 11'h701, 11'h701, 11'h701, 11'h701, 11'h701, 11'h701,
11'h702, 11'h702, 11'h703, 11'h704, 11'h705, 11'h707, 11'h708, 11'h70A, 11'h70B, 11'h70D, 11'h70F, 11'h712, 11'h714, 11'h716,
11'h719, 11'h71C, 11'h71F, 11'h722, 11'h725, 11'h728, 11'h72B, 11'h72F, 11'h733, 11'h736, 11'h73A, 11'h73E, 11'h743, 11'h747,
11'h74B, 11'h750, 11'h754, 11'h759, 11'h75E, 11'h763, 11'h768, 11'h76D, 11'h772, 11'h777, 11'h77C, 11'h782, 11'h787, 11'h78D,
11'h792, 11'h798, 11'h79E, 11'h7A4, 11'h7AA, 11'h7B0, 11'h7B5, 11'h7BB, 11'h7C2, 11'h7C8, 11'h7CE, 11'h7D4, 11'h7DA, 11'h7E0,
11'h7E7, 11'h7ED, 11'h7F3, 11'h7F9
};
logic [39:0] phase_accum;
logic PAL_FLIP = 1'd0;
logic PAL_line_count = 1'd0;
/**************************************
Generate Luma and Chroma Signals
***************************************/
always_ff @(posedge clk) begin
for (logic [3:0] x = 0; x < (MAX_PHASES - 1'd1); x = x + 1'd1) begin
phase[x + 1] <= phase[x];
end
// delay red / blue signals to align luma with U/V calculation (Fixes colorbleeding)
red_1 <= red;
blue_1 <= blue;
red_2 <= red_1;
blue_2 <= blue_1;
// Calculate Luma signal
yr <= {red, 8'd0} + {red, 5'd0}+ {red, 4'd0} + {red, 1'd0};
yg <= {green, 9'd0} + {green, 6'd0} + {green, 4'd0} + {green, 3'd0} + green;
yb <= {blue, 6'd0} + {blue, 5'd0} + {blue, 4'd0} + {blue, 2'd0} + blue;
phase[0].y <= yr + yg + yb;
// Generate the LUT values using the phase accumulator reference.
phase_accum <= phase_accum + PHASE_INC;
chroma_LUT <= phase_accum[39:32];
// Adjust SINE carrier reference for PAL (Also adjust for PAL Switch)
if (PAL_EN) begin
if (PAL_FLIP)
chroma_LUT_BURST <= chroma_LUT + 8'd160;
else
chroma_LUT_BURST <= chroma_LUT + 8'd96;
end else // Adjust SINE carrier reference for NTSC
chroma_LUT_BURST <= chroma_LUT + 8'd128;
// Prepare LUT values for sin / cos (+90 degress)
chroma_LUT_SIN <= chroma_LUT;
chroma_LUT_COS <= chroma_LUT + 8'd64;
// Calculate for U, V - Bit Shift Multiple by u = by * 1024 x 0.492 = 504, v = ry * 1024 x 0.877 = 898
phase[0].u <= $signed({2'b0 ,(blue_2)}) - $signed({2'b0 ,phase[0].y[17:10]});
phase[0].v <= $signed({2'b0 , (red_2)}) - $signed({2'b0 ,phase[0].y[17:10]});
phase[1].u <= 21'($signed({phase[0].u, 8'd0}) + $signed({phase[0].u, 7'd0}) + $signed({phase[0].u, 6'd0}) + $signed({phase[0].u, 5'd0}) + $signed({phase[0].u, 4'd0}) + $signed({phase[0].u, 3'd0}));
phase[1].v <= 21'($signed({phase[0].v, 9'd0}) + $signed({phase[0].v, 8'd0}) + $signed({phase[0].v, 7'd0}) + $signed({phase[0].v, 1'd0}));
phase[0].c <= vref;
phase[1].c <= phase[0].c;
phase[2].c <= phase[1].c;
phase[3].c <= phase[2].c;
if (hsync) begin // Reset colorburst counter, as well as the calculated cos / sin values.
cburst_phase <= 'd0;
phase[2].u <= 21'b0;
phase[2].v <= 21'b0;
phase[4].c <= phase[3].c;
if (PAL_line_count) begin
PAL_FLIP <= ~PAL_FLIP;
PAL_line_count <= ~PAL_line_count;
end
end
else begin // Generate Colorburst for 9 cycles
if (cburst_phase >= COLORBURST_RANGE[16:10] && cburst_phase <= COLORBURST_RANGE[9:0]) begin // Start the color burst signal at 40 samples or 0.9 us
// COLORBURST SIGNAL GENERATION (9 CYCLES ONLY or between count 40 - 240)
phase[2].u <= $signed({chroma_SIN_LUT[chroma_LUT_BURST],5'd0});
phase[2].v <= 21'b0;
// Division to scale down the results to fit 8 bit.
if (PAL_EN)
phase[3].u <= $signed(phase[2].u[20:8]) + $signed(phase[2].u[20:10]) + $signed(phase[2].u[20:14]);
else
phase[3].u <= $signed(phase[2].u[20:8]) + $signed(phase[2].u[20:11]) + $signed(phase[2].u[20:12]) + $signed(phase[2].u[20:13]);
phase[3].v <= phase[2].v;
end else begin // MODULATE U, V for chroma
/*
U,V are both multiplied by 1024 earlier to scale for the decimals in the YUV colorspace conversion.
U and V are both divided by 2^10 which introduce chroma subsampling of 4:1:1 (25% or from 8 bit to 6 bit)
*/
phase[2].u <= $signed((phase[1].u)>>>10) * $signed(chroma_SIN_LUT[chroma_LUT_SIN]);
phase[2].v <= $signed((phase[1].v)>>>10) * $signed(chroma_SIN_LUT[chroma_LUT_COS]);
// Divide U*sin(wt) and V*cos(wt) to fit results to 8 bit
phase[3].u <= $signed(phase[2].u[20:9]) + $signed(phase[2].u[20:10]) + $signed(phase[2].u[20:14]);
phase[3].v <= $signed(phase[2].v[20:9]) + $signed(phase[2].v[20:10]) + $signed(phase[2].u[20:14]);
end
// Stop the colorburst timer as its only needed for the initial pulse
if (cburst_phase <= COLORBURST_RANGE[9:0])
cburst_phase <= cburst_phase + 9'd1;
// Calculate for chroma (Note: "PAL SWITCH" routine flips V * COS(Wt) every other line)
if (PAL_EN) begin
if (PAL_FLIP)
phase[4].c <= vref + phase[3].u - phase[3].v;
else
phase[4].c <= vref + phase[3].u + phase[3].v;
PAL_line_count <= 1'd1;
end else
phase[4].c <= vref + phase[3].u + phase[3].v;
end
// Adjust sync timing correctly
phase[1].hsync <= hsync; phase[1].vsync <= vsync; phase[1].csync <= csync;
phase[2].hsync <= phase[1].hsync; phase[2].vsync <= phase[1].vsync; phase[2].csync <= phase[1].csync;
phase[3].hsync <= phase[2].hsync; phase[3].vsync <= phase[2].vsync; phase[3].csync <= phase[2].csync;
phase[4].hsync <= phase[3].hsync; phase[4].vsync <= phase[3].vsync; phase[4].csync <= phase[3].csync;
hsync_o <= phase[4].hsync; vsync_o <= phase[4].vsync; csync_o <= phase[4].csync;
phase[1].y <= phase[0].y; phase[2].y <= phase[1].y; phase[3].y <= phase[2].y; phase[4].y <= phase[3].y; phase[5].y <= phase[4].y;
// Set Chroma / Luma output
C <= CVBS ? 8'd0 : phase[4].c[7:0];
Y <= CVBS ? ({1'b0, phase[5].y[17:11]} + {1'b0, phase[4].c[7:1]}) : phase[5].y[17:10];
end
assign dout = {C, Y, 8'd0};
endmodule