From d5e11c35c75fab00a8797acf6e7b03e5a516672d Mon Sep 17 00:00:00 2001 From: sorgelig Date: Mon, 5 Mar 2018 17:01:32 +0800 Subject: [PATCH] Update API. --- sys/osd.v | 102 ++++++++++++++++++++++++------------------ sys/sys_top.sdc | 11 ++++- sys/sys_top.v | 39 ++++++++++------ sys/vip_config.sv | 111 ++++++++++++++++++++++++++++++---------------- 4 files changed, 168 insertions(+), 95 deletions(-) diff --git a/sys/osd.v b/sys/osd.v index 6379ceb..f6e8915 100644 --- a/sys/osd.v +++ b/sys/osd.v @@ -7,7 +7,7 @@ module osd input io_osd, input io_strobe, - input [7:0] io_din, + input [15:0] io_din, input clk_video, input [23:0] din, @@ -23,14 +23,16 @@ parameter OSD_Y_OFFSET = 12'd0; localparam OSD_WIDTH = 12'd256; localparam OSD_HEIGHT = 12'd64; -// this core supports only the display related OSD commands -// of the minimig v1 reg osd_enable; -(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[4096]; // the OSD buffer itself +(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[4096]; -reg highres = 0; +reg highres = 0; +reg info = 0; +reg [8:0] infoh; +reg [8:0] infow; +reg [11:0] infox; +reg [21:0] infoy; -// the OSD has its own SPI interface to the io controller always@(posedge clk_sys) begin reg [11:0] bcnt; reg [7:0] cmd; @@ -42,24 +44,37 @@ always@(posedge clk_sys) begin if(~io_osd) begin bcnt <= 0; has_cmd <= 0; + cmd <= 0; + if(cmd[7:4] == 4) osd_enable <= cmd[0]; end else begin if(~old_strobe & io_strobe) begin if(!has_cmd) begin has_cmd <= 1; - cmd <= io_din; + cmd <= io_din[7:0]; // command 0x40: OSDCMDENABLE, OSDCMDDISABLE - if(io_din[7:4] == 4'b0100) begin - osd_enable <= io_din[0]; + if(io_din[7:4] == 4) begin if(!io_din[0]) highres <= 0; + info <= io_din[2]; + bcnt <= 0; end - bcnt <= {io_din[3:0], 8'h00}; - if(io_din[7:3] == 5'b00101) highres <= 1; - end else begin // command 0x20: OSDCMDWRITE - if(cmd[7:4] == 4'b0010) begin - osd_buffer[bcnt] <= io_din; - bcnt <= bcnt + 1'd1; + if(io_din[7:4] == 2) begin + if(io_din[3]) highres <= 1; + bcnt <= {io_din[3:0], 8'h00}; end + end else begin + // command 0x40: OSDCMDENABLE, OSDCMDDISABLE + if(cmd[7:4] == 4) begin + if(bcnt == 0) infox <= io_din[11:0]; + if(bcnt == 1) infoy <= io_din[11:0]; + if(bcnt == 2) infow <= {io_din[5:0], 3'b000}; + if(bcnt == 3) infoh <= {io_din[5:0], 3'b000}; + end + + // command 0x20: OSDCMDWRITE + if(cmd[7:4] == 2) osd_buffer[bcnt] <= io_din[7:0]; + + bcnt <= bcnt + 1'd1; end end end @@ -94,7 +109,8 @@ reg [7:0] osd_byte; reg [21:0] osd_vcnt; reg [21:0] fheight; -wire [21:0] hrheight = (OSD_HEIGHT< {dsp_width, 2'b00}) begin v_cnt <= 0; dsp_height <= v_cnt; - - if(v_cnt<320) begin - multiscan <= 0; - fheight <= hrheight; - end - else if(v_cnt<640) begin - multiscan <= 1; - fheight <= hrheight << 1; - end - else if(v_cnt<960) begin - multiscan <= 2; - fheight <= hrheight + (hrheight<<1); + + if(osd_enable) begin + if(v_cnt<320) begin + multiscan <= 0; + fheight <= hrheight; + finfoy <= infoy; + end + else if(v_cnt<640) begin + multiscan <= 1; + fheight <= hrheight << 1; + finfoy <= infoy << 1; + end + else if(v_cnt<960) begin + multiscan <= 2; + fheight <= hrheight + (hrheight<<1); + finfoy <= infoy + (infoy << 1); + end + else begin + multiscan <= 3; + fheight <= hrheight << 2; + finfoy <= infoy << 2; + end end else begin - multiscan <= 3; - fheight <= hrheight << 2; + fheight <= 0; end end h_cnt <= 0; @@ -148,28 +173,19 @@ always @(posedge clk_video) begin end // area in which OSD is being displayed -wire [21:0] h_osd_start = ((dsp_width - OSD_WIDTH)>>1) + OSD_X_OFFSET; -wire [21:0] h_osd_end = h_osd_start + OSD_WIDTH; -wire [21:0] v_osd_start = ((dsp_height- fheight)>>1) + OSD_Y_OFFSET; +wire [21:0] h_osd_start = info ? infox : ((dsp_width - OSD_WIDTH)>>1) + OSD_X_OFFSET; +wire [21:0] h_osd_end = info ? (h_osd_start + infow) : (h_osd_start + OSD_WIDTH); +wire [21:0] v_osd_start = info ? finfoy : ((dsp_height- fheight)>>1) + OSD_Y_OFFSET; wire [21:0] v_osd_end = v_osd_start + fheight; wire [21:0] osd_hcnt = h_cnt[21:0] - h_osd_start + 1'd1; -wire osd_de = osd_enable && +wire osd_de = osd_enable && fheight && (h_cnt >= h_osd_start) && (h_cnt < h_osd_end) && (v_cnt >= v_osd_start) && (v_cnt < v_osd_end); wire osd_pixel = osd_byte[osd_vcnt[2:0]]; - -// -// -// Pipeline one cycle to improve timing -// -//assign dout = !osd_de ? din : {{osd_pixel, osd_pixel, OSD_COLOR[2], din[23:19]}, -// {osd_pixel, osd_pixel, OSD_COLOR[1], din[15:11]}, -// {osd_pixel, osd_pixel, OSD_COLOR[0], din[7:3]}}; - reg [23:0] rdout; assign dout = rdout; diff --git a/sys/sys_top.sdc b/sys/sys_top.sdc index 8438a16..8d7a795 100644 --- a/sys/sys_top.sdc +++ b/sys/sys_top.sdc @@ -1,3 +1,4 @@ +# Specify root clocks create_clock -period "50.0 MHz" [get_ports FPGA_CLK1_50] create_clock -period "50.0 MHz" [get_ports FPGA_CLK2_50] create_clock -period "50.0 MHz" [get_ports FPGA_CLK3_50] @@ -5,6 +6,7 @@ create_clock -period "100.0 MHz" [get_pins -compatibility_mode *|h2f_user0_clk] derive_pll_clocks +# Specify PLL-generated clock(s) #create_generated_clock -source [get_pins -compatibility_mode {*|pll|pll_inst|altera_pll_i|general[1].gpll~PLL_OUTPUT_COUNTER|divclk}] \ -name SDRAM_CLK [get_ports {SDRAM_CLK}] @@ -18,6 +20,7 @@ create_generated_clock -source [get_pins { pll_hdmi|pll_hdmi_inst|altera_pll_i|c derive_clock_uncertainty +# Set acceptable delays for SDRAM chip (See correspondent chip datasheet) #set_input_delay -max -clock SDRAM_CLK 6.4ns [get_ports SDRAM_DQ[*]] #set_input_delay -min -clock SDRAM_CLK 3.7ns [get_ports SDRAM_DQ[*]] @@ -28,6 +31,7 @@ derive_clock_uncertainty #set_output_delay -max -clock SDRAM_CLK 1.6ns [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] #set_output_delay -min -clock SDRAM_CLK -0.9ns [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] +# Decouple different clock groups (to simplify routing) set_clock_groups -asynchronous \ -group [get_clocks { *|pll|pll_inst|altera_pll_i|general[*].gpll~PLL_OUTPUT_COUNTER|divclk}] \ -group [get_clocks { pll_hdmi|pll_hdmi_inst|altera_pll_i|cyclonev_pll|counter[0].output_counter|divclk VID_CLK}] \ @@ -37,8 +41,13 @@ set_clock_groups -asynchronous \ set_output_delay -max -clock HDMI_CLK 2.0ns [get_ports {HDMI_TX_D[*] HDMI_TX_DE HDMI_TX_HS HDMI_TX_VS}] set_output_delay -min -clock HDMI_CLK -1.5ns [get_ports {HDMI_TX_D[*] HDMI_TX_DE HDMI_TX_HS HDMI_TX_VS}] +# Put constraints on input ports +set_false_path -from [get_ports {KEY*}] -to * +set_false_path -from [get_ports {BTN_*}] -to * + +# Put constraints on output ports set_false_path -from * -to [get_ports {LED_*}] -set_false_path -from * -to [get_ports {BTN_*}] set_false_path -from * -to [get_ports {VGA_*}] +set_false_path -from * -to [get_ports {AUDIO_SPDIF}] set_false_path -from * -to [get_ports {AUDIO_L}] set_false_path -from * -to [get_ports {AUDIO_R}] diff --git a/sys/sys_top.v b/sys/sys_top.v index 4f737d5..76558c3 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -190,6 +190,7 @@ cyclonev_hps_interface_mpu_general_purpose h2f_gp reg [15:0] cfg; reg cfg_got = 0; +reg cfg_set = 0; //wire [2:0] hdmi_res = cfg[10:8]; wire dvi_mode = cfg[7]; wire audio_96k = cfg[6]; @@ -205,6 +206,7 @@ reg [31:0] cfg_custom_p2; reg [4:0] vol_att = 0; +reg vip_newcfg = 0; always@(posedge clk_sys) begin reg [7:0] cmd; reg has_cmd; @@ -224,21 +226,22 @@ always@(posedge clk_sys) begin else begin if(cmd == 1) begin cfg <= io_din; - cfg_got <= 1; + cfg_set <= 1; end if(cmd == 'h20) begin - cfg_got <= 0; + cfg_set <= 0; cnt <= cnt + 1'd1; if(cnt<8) begin + if(!cnt) vip_newcfg <= ~cfg_ready; case(cnt) - 0: WIDTH <= io_din[11:0]; - 1: HFP <= io_din[11:0]; - 2: HS <= 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[11:0]; - 7: VBP <= io_din[11:0]; + 0: if(WIDTH != io_din[11:0]) begin WIDTH <= io_din[11:0]; vip_newcfg <= 1; end + 1: if(HFP != io_din[11:0]) begin HFP <= io_din[11:0]; vip_newcfg <= 1; end + 2: if(HS != io_din[11:0]) begin HS <= io_din[11:0]; vip_newcfg <= 1; end + 3: if(HBP != io_din[11:0]) begin HBP <= io_din[11:0]; vip_newcfg <= 1; end + 4: if(HEIGHT != io_din[11:0]) begin HEIGHT <= io_din[11:0]; vip_newcfg <= 1; end + 5: if(VFP != io_din[11:0]) begin VFP <= io_din[11:0]; vip_newcfg <= 1; end + 6: if(VS != io_din[11:0]) begin VS <= io_din[11:0]; vip_newcfg <= 1; end + 7: if(VBP != io_din[11:0]) begin VBP <= io_din[11:0]; vip_newcfg <= 1; end endcase if(cnt == 1) begin cfg_custom_p1 <= 0; @@ -263,6 +266,16 @@ always@(posedge clk_sys) begin end end +always @(posedge clk_sys) begin + reg vsd, vsd2; + if(~cfg_ready || ~cfg_set) cfg_got <= cfg_set; + else begin + vsd <= HDMI_TX_VS; + vsd2 <= vsd; + if(~vsd2 & vsd) cfg_got <= cfg_set; + end +end + /////////////////////////// RESET /////////////////////////////////// reg reset_req = 0; @@ -368,7 +381,7 @@ vip_config vip_config .ARX(ARX), .ARY(ARY), - .CFG_SET(cfg_got), + .CFG_SET(vip_newcfg & cfg_got), .WIDTH(WIDTH), .HFP(HFP), @@ -652,7 +665,7 @@ osd hdmi_osd .io_osd(io_osd), .io_strobe(io_strobe), - .io_din(io_din[7:0]), + .io_din(io_din), .clk_video(iHdmiClk), .din(hdmi_data), @@ -687,7 +700,7 @@ osd vga_osd .io_osd(io_osd), .io_strobe(io_strobe), - .io_din(io_din[7:0]), + .io_din(io_din), .clk_video(clk_vid), .din(de ? {r_out, g_out, b_out} : 24'd0), diff --git a/sys/vip_config.sv b/sys/vip_config.sv index 68057d7..89bf241 100644 --- a/sys/vip_config.sv +++ b/sys/vip_config.sv @@ -25,58 +25,69 @@ module vip_config input waitrequest ); -reg [31:0] wcalc; -reg [31:0] hcalc; - -wire [31:0] videow = (!VSET && (wcalc > WIDTH)) ? WIDTH : wcalc; -wire [31:0] videoh = VSET ? VSET : (hcalc > HEIGHT) ? HEIGHT : hcalc; - -wire [31:0] posx = (WIDTH - videow)>>1; -wire [31:0] posy = (HEIGHT- videoh)>>1; reg newres = 1; wire [21:0] init[23] = '{ //video mode - {newres, 2'd2, 7'd04, 12'd0 }, //Bank - {newres, 2'd2, 7'd30, 12'd0 }, //Valid - {newres, 2'd2, 7'd05, 12'd0 }, //Progressive/Interlaced - {newres, 2'd2, 7'd06, WIDTH }, //Active pixel count - {newres, 2'd2, 7'd07, HEIGHT }, //Active line count - {newres, 2'd2, 7'd09, HFP }, //Horizontal Front Porch - {newres, 2'd2, 7'd10, HS }, //Horizontal Sync Length - {newres, 2'd2, 7'd11, HFP+HBP+HS }, //Horizontal Blanking (HFP+HBP+HSync) - {newres, 2'd2, 7'd12, VFP }, //Vertical Front Porch - {newres, 2'd2, 7'd13, VS }, //Vertical Sync Length - {newres, 2'd2, 7'd14, VFP+VBP+VS }, //Vertical blanking (VFP+VBP+VSync) - {newres, 2'd2, 7'd30, 12'd1 }, //Valid - {newres, 2'd2, 7'd00, 12'd1 }, //Go + {newres, 2'd2, 7'd04, 12'd0 }, //Bank + {newres, 2'd2, 7'd30, 12'd0 }, //Valid + {newres, 2'd2, 7'd05, 12'd0 }, //Progressive/Interlaced + {newres, 2'd2, 7'd06, w }, //Active pixel count + {newres, 2'd2, 7'd07, h }, //Active line count + {newres, 2'd2, 7'd09, hfp }, //Horizontal Front Porch + {newres, 2'd2, 7'd10, hs }, //Horizontal Sync Length + {newres, 2'd2, 7'd11, hb }, //Horizontal Blanking (HFP+HBP+HSync) + {newres, 2'd2, 7'd12, vfp }, //Vertical Front Porch + {newres, 2'd2, 7'd13, vs }, //Vertical Sync Length + {newres, 2'd2, 7'd14, vb }, //Vertical blanking (VFP+VBP+VSync) + {newres, 2'd2, 7'd30, 12'd1 }, //Valid + {newres, 2'd2, 7'd00, 12'd1 }, //Go //mixer - { 1'd1, 2'd1, 7'd03, WIDTH }, //Bkg Width - { 1'd1, 2'd1, 7'd04, HEIGHT }, //Bkg Height - { 1'd1, 2'd1, 7'd08, posx[11:0] }, //Pos X - { 1'd1, 2'd1, 7'd09, posy[11:0] }, //Pos Y - { 1'd1, 2'd1, 7'd10, 12'd1 }, //Enable Video 0 - { 1'd1, 2'd1, 7'd00, 12'd1 }, //Go + { 1'd1, 2'd1, 7'd03, w }, //Bkg Width + { 1'd1, 2'd1, 7'd04, h }, //Bkg Height + { 1'd1, 2'd1, 7'd08, posx }, //Pos X + { 1'd1, 2'd1, 7'd09, posy }, //Pos Y + { 1'd1, 2'd1, 7'd10, 12'd1 }, //Enable Video 0 + { 1'd1, 2'd1, 7'd00, 12'd1 }, //Go //scaler - { 1'd1, 2'd0, 7'd03, videow[11:0] }, //Output Width - { 1'd1, 2'd0, 7'd04, videoh[11:0] }, //Output Height - { 1'd1, 2'd0, 7'd00, 12'd1 }, //Go + { 1'd1, 2'd0, 7'd03, videow }, //Output Width + { 1'd1, 2'd0, 7'd04, videoh }, //Output Height + { 1'd1, 2'd0, 7'd00, 12'd1 }, //Go 22'h3FFFFF }; +reg [11:0] w; +reg [11:0] hfp; +reg [11:0] hbp; +reg [11:0] hs; +reg [11:0] hb; +reg [11:0] h; +reg [11:0] vfp; +reg [11:0] vbp; +reg [11:0] vs; +reg [11:0] vb; + +reg [11:0] videow; +reg [11:0] videoh; + +reg [11:0] posx; +reg [11:0] posy; + always @(posedge clk) begin reg [7:0] state = 0; reg [7:0] arx, ary; reg [7:0] arxd, aryd; reg [11:0] vset, vsetd; reg cfg, cfgd; - integer timeout = 0; - + reg [31:0] wcalc; + reg [31:0] hcalc; + reg [12:0] timeout = 0; + arxd <= ARX; aryd <= ARY; vsetd <= VSET; @@ -89,23 +100,47 @@ always @(posedge clk) begin arx <= arxd; ary <= aryd; vset <= vsetd; - timeout <= 10000; + timeout <= '1; state <= 0; if(reset || (~cfgd && cfg)) newres <= 1; end else if(timeout > 0) begin - timeout <= timeout - 1; + timeout <= timeout - 1'd1; state <= 1; + if(!(timeout & 'h1f)) case(timeout>>5) + 5: begin + w <= WIDTH; + hfp <= HFP; + hbp <= HBP; + hs <= HS; + h <= HEIGHT; + vfp <= VFP; + vbp <= VBP; + vs <= VS; + end + 4: begin + hb <= hfp+hbp+hs; + vb <= vfp+vbp+vs; + end + 3: begin + wcalc <= vset ? (vset*arx)/ary : (h*arx)/ary; + hcalc <= (w*ary)/arx; + end + 2: begin + videow <= (!vset && (wcalc > w)) ? w : wcalc[11:0]; + videoh <= vset ? vset : (hcalc > h) ? h : hcalc[11:0]; + end + 1: begin + posx <= (w - videow)>>1; + posy <= (h - videoh)>>1; + end + endcase end else if(~waitrequest && state) begin - if(state == 1) begin - wcalc <= VSET ? (VSET*arx)/ary : (HEIGHT*arx)/ary; - hcalc <= (WIDTH*ary)/arx; - end state <= state + 1'd1; write <= 0; if((state&3)==3) begin