⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hdsdi_autodetect_ln.v

📁 SDI接口的源程序,包括扰码编码,并串转换,用VHDL硬件描述语言编写
💻 V
📖 第 1 页 / 共 2 页
字号:
// std_int register
//
// This register holds the detected video standard code.
//
always @ (posedge clk or posedge reset)
    if (reset)
        std_int <= 0;
    else if (ce)
        if (ld_std)
            std_int <= loops;

assign std = std_int;

//
// video timing logic
//
// The following logic generates various video timing signals:
//
// v is the vertical blanking indicator bit and is only valid when eav or sav
// are asserted. v is really just the vid_in[7] bit, but is reassigned to the
// more descriptive v signal.
//
// f is the field indicator bit and is only valid when eav or sav are asserted.
// f is really just the vid_in[8] bit, but is reassigned to the more descriptive
// f signal.
//
// last_v is a register that holds the value of v from the last line. This
// register loads whenever eav is asserted. It is used to detect the rising
// edge of the V signal to generate the first_act signal.
//
// first_act indicates the first active line of a field or frame.  
//
assign v = vid_in[7];
assign f = vid_in[8];

always @ (posedge clk or posedge reset)
    if (reset)
        last_v <= 1'b0;
    else if (ce)
        if (eav)
            last_v <= v;

always @ (posedge clk or posedge reset)
    if (reset)
        first_act <= 1'b0;
    else if (ce)
        if (eav)
            first_act <= last_v & ~v;

//
// locked flip-flop
//
// This flip flop is controlled by the finite state machine.
//
always @ (posedge clk or posedge reset)
    if (reset)
        locked_q <= 1'b0;
    else if (ce)
        begin
            if (clr_locked)
                locked_q <= 1'b0;
            else if (set_locked)
                locked_q <= 1'b1;
        end

assign locked = locked_q;

//
// comparison logic
//
// The comparison logic is used to compare the word and line counts found in 
// the video stream against the known values for the various video standards.
// To reduce the size of the implementation, the word and line counts are
// compared sequentially against the known word and line counts using one
// comparator for the words and one for the lines, rather than doing a parallel
// comparison against all known values. The FSM controls this sequential search.
//
always @ (cmp_mux)
    case (cmp_mux)
        4'b0000:     cmp_wcnt <= 2200;
        4'b0001:     cmp_wcnt <= 2376;
        4'b0010:     cmp_wcnt <= 2200;
        4'b0011:     cmp_wcnt <= 2640;
        4'b0100:     cmp_wcnt <= 2200;
        4'b0101:     cmp_wcnt <= 2640;
        4'b0110:     cmp_wcnt <= 2750;
        4'b0111:     cmp_wcnt <= 1650;
        4'b1000:     cmp_wcnt <= 2750;
        4'b1001:     cmp_wcnt <= 1980;
        default:     cmp_wcnt <= 2200;
    endcase

always @ (cmp_mux)
    case (cmp_mux)
        4'b0000:     cmp_lcnt <= 517;
        4'b0001:     cmp_lcnt <= 540;
        4'b0010:     cmp_lcnt <= 540;
        4'b0011:     cmp_lcnt <= 540;
        4'b0100:     cmp_lcnt <= 1080;
        4'b0101:     cmp_lcnt <= 1080;
        4'b0110:     cmp_lcnt <= 1080;
        4'b0111:     cmp_lcnt <= 720;
        4'b1000:     cmp_lcnt <= 540;
        4'b1001:     cmp_lcnt <= 720;
        default:     cmp_lcnt <= 540;
    endcase

assign cmp_mux = compare_sel ? std_int : loops;
assign match_words = word_counter == cmp_wcnt;
assign match_lines = line_counter == cmp_lcnt;
assign match = match_words & match_lines;

//
// Finite state machine
//
always @ (posedge clk or posedge reset)
    if (reset)
        current_state <= ACQ0;
    else if (ce)
        if (reacquire_sync)
            current_state <= ACQ0;
        else
            current_state <= next_state;

always @ (current_state or sav or first_act or v or loops_tc or 
          match or maxerrs or timeout or f)
    
    case (current_state)
        ACQ0:   if (sav & first_act)
                    next_state <= ACQ1;
                else
                    next_state <= ACQ0;

        ACQ1:   if (sav)
                    next_state <= ACQ2;
                else
                    next_state <= ACQ1;

        ACQ2:   if (sav & v)
                    next_state <= ACQ3;
                else
                    next_state <= ACQ2;

        ACQ3:   next_state <= ACQ4;

        ACQ4:   if (match)
                    next_state <= LCK0;
                else if (loops_tc)
                    next_state <= ACQ0;
                else
                    next_state <= ACQ4;

        LCK0:   if (timeout)
                    next_state <= ERR;
                else if (sav & first_act & ~f)
                    next_state <= LCK1;
                else
                    next_state <= LCK0;

        LCK1:   if (timeout)
                    next_state <= ERR;
                else if (sav)
                    next_state <= LCK2;
                else 
                    next_state <= LCK1;

        LCK2:   if (timeout)
                    next_state <= ERR;
                else if (sav & v)
                    next_state <= LCK3;
                else
                    next_state <= LCK2;

        LCK3:   if (match)
                    next_state <= LCK0;
                else
                    next_state <= ERR;

        ERR:    if (maxerrs)
                    next_state <= ACQ0;
                else
                    next_state <= LCK0;

        default:
                next_state <= ACQ0;
    endcase

always @ (current_state or sav or first_act or match)
begin
    en_wcnt         <= 1'b0;
    en_lcnt         <= 1'b0;
    clr_wcnt        <= 1'b0;
    clr_lcnt        <= 1'b0;
    set_locked      <= 1'b0;
    clr_locked      <= 1'b0;
    clr_errcnt      <= 1'b0;
    inc_errcnt      <= 1'b0;
    clr_loops       <= 1'b0;
    inc_loops       <= 1'b0;
    ld_std          <= 1'b0;
    compare_sel     <= 1'b0;

    case (current_state)
        
        ACQ0:   begin
                    clr_errcnt <= 1'b1;
                    clr_locked <= 1'b1;
                    clr_wcnt <= 1'b1;
                    clr_lcnt <= 1'b1;
                end

        ACQ1:   begin
                    en_wcnt <= 1'b1;
                    en_lcnt <= 1'b1;
                end

        ACQ2:   en_lcnt <= 1'b1;

        ACQ3:   begin
                    clr_loops <= 1'b1;
                end

        ACQ4:   begin
                    inc_loops <= 1'b1;
                    ld_std <= 1'b1;
                    if (match)
                        clr_wcnt <= 1'b1;
                end

        LCK0:   begin
                    set_locked <= 1'b1;
                    en_wcnt <= 1'b1;
                    clr_lcnt <= 1'b1;
                    compare_sel <= 1'b1;
                    if (sav)
                        clr_wcnt <= 1'b1;
                end

        LCK1:   begin
                    en_wcnt <= 1'b1;
                    en_lcnt <= 1'b1;
                    compare_sel <= 1'b1;
                end
        
        LCK2:   begin
                    en_lcnt <= 1'b1;
                    compare_sel <= 1'b1;
                end
        
        LCK3:   begin
                    compare_sel <= 1'b1;
                    clr_wcnt <= 1'b1;
                    if (match) clr_errcnt <= 1'b1;
                end
        
        ERR:    begin
                    inc_errcnt <= 1'b1;
                    clr_wcnt <= 1'b1;
                    compare_sel <= 1'b1;
                end
    endcase
end

//
// Reset logic
//
// The reset signal is maintained to the logic in this module for a few
// clock cycles after the global reset signal is removed.
//
assign reset = rst | ~reset_delay[7];

always @ (posedge clk or posedge rst)
    if (rst)
        reset_delay <= 0;
    else
        reset_delay <= {reset_delay[6:0], 1'b1};

//
// ln generator
//
// This code implements the line number generator. The line number generator
// is a counter that increments on the XYZ word of each EAV. It is initialized
// on the first active line of either  field. The initial value depends on
// the current standard and the field bit. The counter wraps back to zero when 
// it reaches the maximum line count for the current standard.
//
always @ (posedge clk or posedge rst)
    if (rst)
        std_reg <= 4'b0000;
    else if (ce)
        if (set_locked)
            std_reg <= std_int;


assign ln_load = last_v & ~v;


always @ (posedge clk or posedge rst)
    if (rst)
        ln_valid_q <= 1'b0;
    else if (ce)
        if (~locked_q)
            ln_valid_q <= 1'b0;
        else if (eav & ln_load)
            ln_valid_q <= 1'b1;

assign ln_valid = ln_valid_q;

always @ (std_reg or f)
    case({std_reg, f})
        // SMPTE 260M 1035i 30Hz
        5'b0000_0: ln_init <= 11'd41;
        5'b0000_1: ln_init <= 11'd603;
    
        // SMPTE 295M 1080i 25Hz
        5'b0001_0: ln_init <= 11'd81;
        5'b0001_1: ln_init <= 11'd706;
    
        // SMPTE 274M 1080i or 1080sF 30Hz
        5'b0010_0: ln_init <= 11'd21;
        5'b0010_1: ln_init <= 11'd584;
    
        // SMPTE 274M 1080i or 1080sF 25 Hz
        5'b0011_0: ln_init <= 11'd21;
        5'b0011_1: ln_init <= 11'd584;
    
        // SMPTE 274M 1080p 30Hz
        5'b0100_0: ln_init <= 11'd42;
        5'b0100_1: ln_init <= 11'd42;
    
        // SMPTE 274M 1080p 25Hz
        5'b0101_0: ln_init <= 11'd42;
        5'b0101_1: ln_init <= 11'd42;
    
        // SMPTE 274M 1080p 24Hz
        5'b0110_0: ln_init <= 11'd42;
        5'b0110_1: ln_init <= 11'd42;
    
        // SMPTE 296M 720p 60Hz or 50Hz
        5'b0111_0: ln_init <= 11'd26;
        5'b0111_1: ln_init <= 11'd26;
        5'b1001_0: ln_init <= 11'd26;
        5'b1001_1: ln_init <= 11'd26;
    
        // SMPTE 274M 1080sF 24Hz
        5'b1000_0: ln_init <= 11'd21;
        5'b1000_1: ln_init <= 11'd584;

        default: ln_init <= 11'd21;     
    endcase                    

always @ (std_reg)
    case(std_reg)
        4'b0000: ln_max <= 11'd1125;
        4'b0001: ln_max <= 11'd1250;
        4'b0010: ln_max <= 11'd1125;
        4'b0011: ln_max <= 11'd1125;
        4'b0100: ln_max <= 11'd1125;
        4'b0101: ln_max <= 11'd1125;
        4'b0110: ln_max <= 11'd1125;
        4'b0111: ln_max <= 11'd750;
        4'b1000: ln_max <= 11'd1125;
        4'b1001: ln_max <= 11'd750;
        default: ln_max <= 11'd1125;
    endcase

assign ln_tc = ln_counter == ln_max;

always @ (posedge clk or posedge rst)
    if (rst)
        ln_counter <= 11'd1;
    else if (ce & eav) 
        begin
            if (ln_load)
                ln_counter <= ln_init;
            else if (ln_tc)
                ln_counter <= 11'd1;
            else
                ln_counter <= ln_counter + 1;
        end

assign ln = ln_counter;

endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -