assign serial_in = serial_out; // tx goes to rx, so that we know that our UART works at least in terms of logic-wise
assign serial_in = serial_out; // tx goes to rx, so that we know that our UART works at least in terms of logic-wise
`ifdef FORMAL
`ifdef FORMAL
localparam Rx_IDLE = 4'b0000;
localparam Rx_IDLE = 4'b0000;
localparam Rx_START_BIT = 4'b0001;
localparam Rx_START_BIT = 4'b0001;
localparam Rx_DATA_BIT_0 = 4'b0010;
localparam Rx_DATA_BIT_0 = 4'b0010;
localparam Rx_DATA_BIT_1 = 4'b0011;
localparam Rx_DATA_BIT_1 = 4'b0011;
localparam Rx_DATA_BIT_2 = 4'b0100;
localparam Rx_DATA_BIT_2 = 4'b0100;
localparam Rx_DATA_BIT_3 = 4'b0101;
localparam Rx_DATA_BIT_3 = 4'b0101;
localparam Rx_DATA_BIT_4 = 4'b0110;
localparam Rx_DATA_BIT_4 = 4'b0110;
localparam Rx_DATA_BIT_5 = 4'b0111;
localparam Rx_DATA_BIT_5 = 4'b0111;
localparam Rx_DATA_BIT_6 = 4'b1000;
localparam Rx_DATA_BIT_6 = 4'b1000;
localparam Rx_DATA_BIT_7 = 4'b1001;
localparam Rx_DATA_BIT_7 = 4'b1001;
localparam Rx_PARITY_BIT = 4'b1010;
localparam Rx_PARITY_BIT = 4'b1010;
localparam Rx_STOP_BIT = 4'b1011;
localparam Rx_STOP_BIT = 4'b1011;
localparam NUMBER_OF_RX_SYNCHRONIZERS = 3; // three FF synhronizers for clock domain crossing
localparam NUMBER_OF_RX_SYNCHRONIZERS = 3; // three FF synhronizers for clock domain crossing
localparam CLOCKS_PER_BIT = 8;
localparam CLOCKS_PER_BIT = 8;
reg had_been_enabled; // a signal to latch Tx 'enable' signal
reg had_been_enabled; // a signal to latch Tx 'enable' signal
reg[($clog2(NUMBER_OF_BITS)-1) : 0] tx_state; // to track the number of transmitter clock cycles (baud_clk) incurred between assertion of 'tx_in_progress' signal from Tx and assertion of 'data_is_valid' signal from Rx
reg[($clog2(NUMBER_OF_BITS)-1) : 0] tx_state; // to track the number of transmitter clock cycles (baud_clk) incurred between assertion of 'tx_in_progress' signal from Tx and assertion of 'data_is_valid' signal from Rx
reg tx_in_progress;
reg tx_in_progress;
reg first_clock_passed_tx, first_clock_passed_rx;
reg first_clock_passed_tx, first_clock_passed_rx;
initial begin
initial begin
had_been_enabled = 0;
had_been_enabled = 0;
tx_state = 0;
tx_state = 0;
tx_in_progress = 0;
tx_in_progress = 0;
first_clock_passed_tx = 0;
first_clock_passed_tx = 0;
first_clock_passed_rx = 0;
first_clock_passed_rx = 0;
end
end
// refer to https://www.allaboutcircuits.com/technical-articles/the-uart-baud-rate-clock-how-accurate-does-it-need-to-be/ for feasible ratio of tx_clk/rx_clk
// refer to https://www.allaboutcircuits.com/technical-articles/the-uart-baud-rate-clock-how-accurate-does-it-need-to-be/ for feasible ratio of tx_clk/rx_clk
localparam rx_clk_increment = 129135; // rx_clk is slower than tx_clk by a factor of 1.015 or equivalently slower than $global_clock by a factor of (1.015*4)
localparam rx_clk_increment = 129135; // rx_clk is slower than tx_clk by a factor of 1.015 or equivalently slower than $global_clock by a factor of (1.015*4)
always @($global_clock) // generation of rx_clk which is 1.5% frequency deviation from tx_clk
always @($global_clock) // generation of rx_clk which is 1.5% frequency deviation from tx_clk
begin
begin
if(reset_rx) begin
if(reset_rx) begin
rx_clk <= 0;
rx_clk <= 0;
counter_rx_clk <= 0;
counter_rx_clk <= 0;
end
end
else begin
else begin
{ rx_clk, counter_rx_clk} <= counter_rx_clk + rx_clk_increment; // the actual rx_clk is slower than tx_clk by a factor 1.015 or 1.5 percent
{ rx_clk, counter_rx_clk} <= counter_rx_clk + rx_clk_increment; // the actual rx_clk is slower than tx_clk by a factor 1.015 or 1.5 percent
//if(counter_rx_clk + rx_clk_increment > {counter_rx_clk_bit_width{1'b1}}) counter_rx_clk <= 0; // restarting from zero when the addition result exceeding the maximum bitwidth
//if(counter_rx_clk + rx_clk_increment > {counter_rx_clk_bit_width{1'b1}}) counter_rx_clk <= 0; // restarting from zero when the addition result exceeding the maximum bitwidth
end
end
end
end
localparam TX_CLK_THRESHOLD = 4; // divides $global_clock by 4 to obtain ck_stb which is just a clock enable signal
localparam TX_CLK_THRESHOLD = 4; // divides $global_clock by 4 to obtain ck_stb which is just a clock enable signal
assert((tx_clk && $past(tx_clk)) == 0); // asserts that tx_clk is only single pulse HIGH
assert((tx_clk && $past(tx_clk)) == 0); // asserts that tx_clk is only single pulse HIGH
assert((($past(counter_tx_clk) - counter_tx_clk) == (TX_CLK_THRESHOLD-1'b1)) || ((counter_tx_clk - $past(counter_tx_clk)) == 1)); // to keep the increasing trend for induction test purpose such that tx_clk occurs at the correct period interval
assert((($past(counter_tx_clk) - counter_tx_clk) == (TX_CLK_THRESHOLD-1'b1)) || ((counter_tx_clk - $past(counter_tx_clk)) == 1)); // to keep the increasing trend for induction test purpose such that tx_clk occurs at the correct period interval
assign stop_bit_location = (tx_state < NUMBER_OF_BITS) ? (NUMBER_OF_BITS - 1 - tx_state) : 0; // if not during UART transmission, set to zero as default for no specific reason
assign stop_bit_location = (tx_state < NUMBER_OF_BITS) ? (NUMBER_OF_BITS - 1 - tx_state) : 0; // if not during UART transmission, set to zero as default for no specific reason
|| (($past(baud_clk)) && $past(had_been_enabled)))) begin // ((just finished transmitting the END bit, but baud_clk still not asserted yet) OR (still busy transmitting) OR (just enabled) OR (END bit finishes transmission with baud_clk asserted, and Tx is enabled immediately after this))
|| (($past(baud_clk)) && $past(had_been_enabled)))) begin // ((just finished transmitting the END bit, but baud_clk still not asserted yet) OR (still busy transmitting) OR (just enabled) OR (END bit finishes transmission with baud_clk asserted, and Tx is enabled immediately after this))
assert(tx_in_progress);
assert(tx_in_progress);
end
end
else begin
else begin
assert(!tx_in_progress);
assert(!tx_in_progress);
end
end
end
end
`ifdef LOOPBACK
`ifdef LOOPBACK
// In a Tx->Rx joint proof, we want to assert that all the bits received by the receiver at any given point in time are equal to all the bits sent by the transmitter
// In a Tx->Rx joint proof, we want to assert that all the bits received by the receiver at any given point in time are equal to all the bits sent by the transmitter
always @(posedge tx_clk) begin
always @(posedge tx_clk) begin
if(first_clock_passed_tx && $past(reset_tx)) begin
if(first_clock_passed_tx && $past(reset_tx)) begin
assert(tx_state == 0);
assert(tx_state == 0);
end
end
end
end
always @(posedge rx_clk) begin // for induction, checks the relationship between Tx 'tx_state' and Rx 'rx_state'
always @(posedge rx_clk) begin // for induction, checks the relationship between Tx 'tx_state' and Rx 'rx_state'
if(first_clock_passed_tx && first_clock_passed_rx) begin
if(first_clock_passed_tx && first_clock_passed_rx) begin
if((rx_state == Rx_IDLE) && ($past(rx_state) == Rx_IDLE)) begin
if((rx_state == Rx_IDLE) && ($past(rx_state) == Rx_IDLE)) begin
wire tx_shift_reg_contains_data_bits = ((tx_in_progress) && (tx_state > 1) && (tx_state < (INPUT_DATA_WIDTH + PARITY_ENABLED))); // shift_reg is one clock cycle before the data bits get registered to serial_out
wire tx_shift_reg_contains_data_bits = ((tx_in_progress) && (tx_state > 1) && (tx_state < (INPUT_DATA_WIDTH + PARITY_ENABLED))); // shift_reg is one clock cycle before the data bits get registered to serial_out
// for induction purpose, checks whether the Tx PISO shift_reg is shifting out all 'INPUT_DATA_WIDTH' data bits correctly
// for induction purpose, checks whether the Tx PISO shift_reg is shifting out all 'INPUT_DATA_WIDTH' data bits correctly
else if(tx_state == NUMBER_OF_BITS) begin // UART stop bit transmission which signifies the end of UART transmission
else if(tx_state == NUMBER_OF_BITS) begin // UART stop bit transmission which signifies the end of UART transmission
assert(serial_out == 1); // stop bit
assert(serial_out == 1); // stop bit
if(($past(enable) && !($past(o_busy)) && (had_been_enabled)) | (shift_reg != 0)) begin // Tx is requested to start next series of data transmission OR Tx is now being prepared for the next series
if(($past(enable) && !($past(o_busy)) && (had_been_enabled)) | (shift_reg != 0)) begin // Tx is requested to start next series of data transmission OR Tx is now being prepared for the next series