📄 auto_baud_with_tracking.v
字号:
// This is the CLOCK_FACTOR_PP prescaler and also mid_bit_count counter
assign enable_clock_count = measure || (verify && main_count_rollover);
always @(posedge clk_i or posedge reset_i)
begin
if (reset_i) clock_count <= 0;
else if (clear_counters) clock_count <= 0;
else if (enable_clock_count)
begin // Must have been clk_i edge
if (clock_count_rollover) clock_count <= 0;
else clock_count <= clock_count + 1;
end
end
// Counter rollover condition
assign clock_count_rollover = (clock_count == (CLOCK_FACTOR_PP-1));
// This condition signals the middle of a bit time, for use during the
// verify stage. Also, this signal is used to advance the main count,
// instead of "clock_count_rollover." This produces an effective "rounding"
// operation for the measurement (which would otherwise "truncate" any
// fraction of time contained in this counter at the instant the measurement
// is finished.
// (The "enable_clock_count" is included in order to make the pulse narrow,
// only one clock wide...)
assign mid_bit_count = (
(clock_count == ((CLOCK_FACTOR_PP>>1)-1))
&& enable_clock_count
);
// This is the main counter. During measurement, it advances once for
// each CLOCK_FACTOR_PP cycles of clk_i. This accumulated measurement
// is then latched into "measurement" when the state machine determines that
// the measurement interval is finished.
// During verify time (when the new candidate baud rate clock is being tested)
// this counter is allowed to run freely, advancing once each clk_i, but being
// reset when it reaches a total count of "measurement" clock cycles.
always @(posedge clk_i or posedge reset_i)
begin
if (reset_i) main_count <= 0;
else // must have been clk_i edge
begin
// Clear main count when measurement is done
if (clear_counters) main_count <= 0;
// If measuring, advance once per CLOCK_FACTOR_PP clk_i pulses.
else if (measure && mid_bit_count) main_count <= main_count + 1;
// If verifying or running, check reset conditions,
// otherwise advance always.
else if (verify)
begin
if (main_count_rollover) main_count <= 0;
else main_count <= main_count + 1;
end
end
end
// This is the "verify" baud clock signal... not the final output one.
assign main_count_rollover = (main_count == measurement);
// This is the BAUD counter. Once a measurement has been verified, it is
// stored in "baud" and the signal "run" goes high. From then on, this
// counter is allowed to run freely, advancing once each clk_i, but being
// reset when it reaches a total count of "baud" clock cycles. This
// counter's reset signal is the output baud rate clock.
always @(posedge clk_i or posedge reset_i)
begin
if (reset_i) baud_count <= 0;
else // must have been clk_i edge
begin
// If running, advance freely
if (run)
begin
if (baud_count_rollover) baud_count <= 0;
else baud_count <= baud_count + 1;
end
end
end
assign baud_count_rollover = (baud_count == baud);
// This is a shift register used to provide "target" character bits one at
// a time for verification as they are "received" (sampled) using the
// candidate baud clock.
always @(posedge clk_i or posedge reset_i)
begin
if (reset_i) target_bits <= `TEMPLATE_BITS;
else // must have been a clock edge
begin
if (~verify) target_bits <= `TEMPLATE_BITS;
if (verify && mid_bit_count) target_bits <= {0,(target_bits>>1)};
end
end
// It is done when only the stop bit is left in the shift register.
assign verify_done = (
(target_bits == 1)
&& verify
&& mid_bit_count
);
// This is a flip-flop used to keep track of whether the verify operation
// is succeeding or not. Any target bits that do not match the received
// data at the sampling edge, will cause the verify_failed bit to go high.
// This is what the state machine looks at to determine whether it passed
// or not.
always @(posedge clk_i or posedge reset_i)
begin
if (reset_i) character_miscompare <= 0;
else // Must have been a clock edge
begin
if (idle) character_miscompare <= 0;
if (verify && mid_bit_count
&& (target_bits[0] ^ serial_dat_i)) character_miscompare <= 1;
end
end
// This is the measurement storage latch. The final measured time count
// from main_count is stored in this latch upon completion of the measurement
// interval. The value stored in this latch is used for the baud clock
// generated during verify, but a different register holds the actual value
// being used to generate output.
always @(posedge clk_i or posedge idle)
begin
// Set to all ones during idle (asynchronous).
if (idle) measurement <= -1;
// Otherwise, there must have been a clk_i edge
// When the measurement is done, the counters are cleared, and the time
// interval must be stored before it is cleared away...
// This also causes a store following a failed verify state on the way back
// into idle, but the idle state clears out the false measurement anyway.
else if (clear_counters) measurement <= (main_count>>1);
end
// This is the BAUD storage latch. The final verified time count
// from the "measurement" register is stored in this register after a good
// verify. The value stored in this latch is used in conjunction with
// baud_count to produce the baud clock which is sent to the output.
always @(posedge clk_i or posedge reset_i)
begin
// Set to all ones during reset (asynchronous).
if (reset_i) baud <= -1;
// Otherwise, there must have been a clk_i edge
// When the measurement is done, the counters are cleared, and the time
// interval must be stored before it is cleared away...
// This also causes a store following a failed verify state on the way back
// into idle, but the idle state clears out the false measurement anyway.
else if (verify_good) baud <= measurement;
end
// This is a flip-flop used to keep track of whether the unit is producing
// a baud clock or not. Initially following reset, there is no baud clock
// being produced. But, once a single measurement is verified, then the
// clock is produced and tracking changes are made over time. Thus, this
// bit goes high as a result of the first "verify_good" pulse, and it remains
// high forever, until the unit is reset.
always @(posedge clk_i or posedge reset_i)
begin
if (reset_i) run <= 0;
else // Must have been a clock edge
begin
if (verify_good) run <= 1;
end
end
assign baud_clk_o = baud_count_rollover;
// This is state machine m1. It checks the status of the serial_dat_i line
// and coordinates the measurement of the time interval of the first two
// bits of the received character, which is the "measurement interval."
// Following the measurement interval, the state machine enters a new
// phase of bit verification. If the measured time interval is accurate
// enough to measure the remaining 8 bits of the character correctly, then
// the measurement is accepted, and the baud rate clock is driven onto
// the baud_clk_o output pin. Incidentally, the process of verification
// effectively filters out all characters which are not the desired target
// character for measurement. In this case, the target character is the
// carriage return.
// State register
always @(posedge clk_i or posedge reset_i)
begin : m1_state_register
if (reset_i) m1_state <= m1_idle; // asynchronous reset
else m1_state <= m1_next_state;
end
// State transition logic
always @(m1_state
or mid_bit_count
or serial_dat_i
or verify_done
or character_miscompare
)
begin : m1_state_logic
// Default values for outputs. The individual states can override these.
idle <= 1'b0;
verify_good <= 1'b0;
measure <= 1'b0;
clear_counters <= 1'b0;
verify <= 1'b0;
case (m1_state) // synthesis parallel_case
m1_idle :
begin
idle <= 1'b1;
if (serial_dat_i == 0) m1_next_state <= m1_measure_0;
else m1_next_state <= m1_idle;
end
m1_measure_0 :
begin
measure <= 1'b1;
// Check at mid bit time, to make sure serial line is still low...
// (At this time, "mid_bit_count" is simply CLOCK_FACTOR_PP>>1 clk_i's.)
if (mid_bit_count && ~serial_dat_i) m1_next_state <= m1_measure_1;
// If it is not low, then it must have been a "glitch"...
else if (mid_bit_count && serial_dat_i) m1_next_state <= m1_idle;
else m1_next_state <= m1_measure_0;
end
m1_measure_1 :
begin
measure <= 1'b1;
// Look for first data bit (high).
if (serial_dat_i) m1_next_state <= m1_measure_2;
// If it is not high keep waiting...
// (Put detection of measurement overflow in here if necessary...)
else m1_next_state <= m1_measure_1;
end
m1_measure_2 :
begin
measure <= 1'b1;
// Check using mid bit time, to make sure serial line is still high...
// (At this time, "mid_bit_count" is simply CLOCK_FACTOR_PP>>1 clk_i's.)
if (mid_bit_count && serial_dat_i) m1_next_state <= m1_measure_3;
// If it is not high, then it must have been a "glitch"...
else if (mid_bit_count && ~serial_dat_i) m1_next_state <= m1_idle;
else m1_next_state <= m1_measure_2;
end
m1_measure_3 :
begin
measure <= 1'b1;
// Look for end of measurement interval (low)
if (!serial_dat_i) m1_next_state <= m1_measure_4;
// If it is not high keep waiting...
// (Put detection of measurement overflow in here if necessary...)
else m1_next_state <= m1_measure_3;
end
// This state outputs a reset pulse, to clear counters and store the
// measurement from main_count.
m1_measure_4 :
begin
clear_counters <= 1'b1; // Clears counters, stores measurement
m1_next_state <= m1_verify_0;
end
m1_verify_0 : // Wait for verify operations to finish
begin
verify <= 1'b1;
if (verify_done) m1_next_state <= m1_verify_1;
else m1_next_state <= m1_verify_0;
end
// NOTE: This "extra" state is needed because the character_miscompare
// information is not valid until 1 cycle after verify_done is
// active.
m1_verify_1 : // Checks for character miscompare
begin
if (character_miscompare) m1_next_state <= m1_verify_failed;
else m1_next_state <= m1_run;
end
m1_verify_failed : // Resets counters on the way back to idle
begin
clear_counters <= 1'b1;
m1_next_state <= m1_idle;
end
// This state is for successful verification results!
// Since this is a tracking unit, the "run" output is used as a pulse
// to store the now verified rate.
m1_run :
begin
verify_good <= 1'b1;
m1_next_state <= m1_idle;
end
default : m1_next_state <= m1_idle;
endcase
end
assign auto_baud_locked_o = run;
endmodule
//`undef LOG2_MAX_CLOCK_FACTOR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -