📄 hdsdi_autodetect_ln.v
字号:
// 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 + -