Line 19... |
Line 19... |
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015-2018, Gisselquist Technology, LLC
|
// Copyright (C) 2015-2019, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// This program is free software (firmware): you can redistribute it and/or
|
// modify it under the terms of the GNU General Public License as published
|
// modify it under the terms of the GNU General Public License as published
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
Line 59... |
Line 59... |
`define RXUL_WAIT 4'h9
|
`define RXUL_WAIT 4'h9
|
`define RXUL_IDLE 4'hf
|
`define RXUL_IDLE 4'hf
|
|
|
module rxuartlite(i_clk, i_uart_rx, o_wr, o_data);
|
module rxuartlite(i_clk, i_uart_rx, o_wr, o_data);
|
parameter TIMER_BITS = 10;
|
parameter TIMER_BITS = 10;
|
|
`ifdef FORMAL
|
|
parameter [(TIMER_BITS-1):0] CLOCKS_PER_BAUD = 16; // Necessary for formal proof
|
|
`else
|
parameter [(TIMER_BITS-1):0] CLOCKS_PER_BAUD = 868; // 115200 MBaud at 100MHz
|
parameter [(TIMER_BITS-1):0] CLOCKS_PER_BAUD = 868; // 115200 MBaud at 100MHz
|
|
`endif
|
localparam TB = TIMER_BITS;
|
localparam TB = TIMER_BITS;
|
input wire i_clk;
|
input wire i_clk;
|
input wire i_uart_rx;
|
input wire i_uart_rx;
|
output reg o_wr;
|
output reg o_wr;
|
output reg [7:0] o_data;
|
output reg [7:0] o_data;
|
Line 110... |
Line 114... |
half_baud_time <= (!ck_uart)&&(chg_counter >= half_baud-1'b1-1'b1);
|
half_baud_time <= (!ck_uart)&&(chg_counter >= half_baud-1'b1-1'b1);
|
|
|
|
|
initial state = `RXUL_IDLE;
|
initial state = `RXUL_IDLE;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
begin
|
|
if (state == `RXUL_IDLE)
|
if (state == `RXUL_IDLE)
|
begin // Idle state, independent of baud counter
|
begin // Idle state, independent of baud counter
|
// By default, just stay in the IDLE state
|
// By default, just stay in the IDLE state
|
state <= `RXUL_IDLE;
|
state <= `RXUL_IDLE;
|
if ((!ck_uart)&&(half_baud_time))
|
if ((!ck_uart)&&(half_baud_time))
|
Line 129... |
Line 132... |
// Data arrives least significant bit first.
|
// Data arrives least significant bit first.
|
// By the time this is clocked in, it's what
|
// By the time this is clocked in, it's what
|
// you'll have.
|
// you'll have.
|
state <= state + 1;
|
state <= state + 1;
|
end
|
end
|
end
|
|
|
|
// Data bit capture logic.
|
// Data bit capture logic.
|
//
|
//
|
// This is drastically simplified from the state machine above, based
|
// This is drastically simplified from the state machine above, based
|
// upon: 1) it doesn't matter what it is until the end of a captured
|
// upon: 1) it doesn't matter what it is until the end of a captured
|
Line 201... |
Line 203... |
`define FORMAL_VERILATOR
|
`define FORMAL_VERILATOR
|
`endif
|
`endif
|
`endif
|
`endif
|
|
|
`ifdef FORMAL
|
`ifdef FORMAL
|
|
|
`define ASSUME assume
|
`define ASSUME assume
|
|
`define ASSERT assert
|
`define PHASE_ONE_ASSERT assert
|
`ifdef VERIFIC
|
`define PHASE_TWO_ASSERT assert
|
(* gclk *) wire gbl_clk;
|
|
global clocking @(posedge gbl_clk); endclocking
|
`ifdef PHASE_TWO
|
|
`undef PHASE_ONE_ASSERT
|
|
`define PHASE_ONE_ASSERT assume
|
|
`endif
|
`endif
|
|
|
|
|
localparam F_CKRES = 10;
|
localparam F_CKRES = 10;
|
|
|
wire f_tx_start, f_tx_busy;
|
(* anyseq *) wire f_tx_start;
|
wire [(F_CKRES-1):0] f_tx_step;
|
(* anyconst *) wire [(F_CKRES-1):0] f_tx_step;
|
reg f_tx_zclk;
|
reg f_tx_zclk;
|
reg [(TB-1):0] f_tx_timer;
|
reg [(TB-1):0] f_tx_timer;
|
wire [7:0] f_rx_newdata;
|
wire [7:0] f_rx_newdata;
|
reg [(TB-1):0] f_tx_baud;
|
reg [(TB-1):0] f_tx_baud;
|
wire f_tx_zbaud;
|
wire f_tx_zbaud;
|
|
|
wire [(TB-1):0] f_max_baud_difference;
|
wire [(TB-1):0] f_max_baud_difference;
|
reg [(TB-1):0] f_baud_difference;
|
reg [(TB-1):0] f_baud_difference;
|
reg [(TB+3):0] f_tx_count, f_rx_count;
|
reg [(TB+3):0] f_tx_count, f_rx_count;
|
wire [7:0] f_tx_data;
|
(* anyseq *) wire [7:0] f_tx_data;
|
|
|
|
|
|
|
wire f_txclk;
|
wire f_txclk;
|
reg [1:0] f_rx_clock;
|
reg [1:0] f_rx_clock;
|
Line 238... |
Line 237... |
|
|
initial f_past_valid = 1'b0;
|
initial f_past_valid = 1'b0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
f_past_valid <= 1'b1;
|
f_past_valid <= 1'b1;
|
|
|
`ifdef F_OPT_CLK2FFLOGIC
|
|
initial f_rx_clock = 3'h0;
|
initial f_rx_clock = 3'h0;
|
always @($global_clock)
|
always @($global_clock)
|
f_rx_clock <= f_rx_clock + 1'b1;
|
f_rx_clock <= f_rx_clock + 1'b1;
|
|
|
always @(*)
|
always @(*)
|
assume(i_clk == f_rx_clock[1]);
|
assume(i_clk == f_rx_clock[1]);
|
`endif
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
//
|
//
|
Line 272... |
Line 269... |
localparam [(F_CKRES-1):0] F_MAXSTEP = F_MIDSTEP + F_HALFSTEP - 1;
|
localparam [(F_CKRES-1):0] F_MAXSTEP = F_MIDSTEP + F_HALFSTEP - 1;
|
|
|
initial assert(F_MINSTEP <= F_MIDSTEP);
|
initial assert(F_MINSTEP <= F_MIDSTEP);
|
initial assert(F_MIDSTEP <= F_MAXSTEP);
|
initial assert(F_MIDSTEP <= F_MAXSTEP);
|
|
|
`ifdef F_OPT_CLK2FFLOGIC
|
|
assign f_tx_step = $anyconst;
|
|
// assume((f_tx_step >= F_MINSTEP)&&(f_tx_step <= F_MAXSTEP));
|
// assume((f_tx_step >= F_MINSTEP)&&(f_tx_step <= F_MAXSTEP));
|
//
|
//
|
//
|
//
|
always @(*) assume((f_tx_step == F_MINSTEP)
|
always @(*) assume((f_tx_step == F_MINSTEP)
|
||(f_tx_step == F_MIDSTEP)
|
||(f_tx_step == F_MIDSTEP)
|
||(f_tx_step == F_MAXSTEP));
|
||(f_tx_step == F_MAXSTEP));
|
|
|
// initial rx_clock = $anyseq;
|
|
always @($global_clock)
|
always @($global_clock)
|
f_tx_clock <= f_tx_clock + f_tx_step;
|
f_tx_clock <= f_tx_clock + f_tx_step;
|
|
|
assign f_txclk = f_tx_clock[F_CKRES-1];
|
assign f_txclk = f_tx_clock[F_CKRES-1];
|
`else
|
|
assign f_tx_clk = i_clk;
|
|
`endif
|
|
//
|
//
|
initial f_past_valid_tx = 1'b0;
|
initial f_past_valid_tx = 1'b0;
|
always @(posedge f_txclk)
|
always @(posedge f_txclk)
|
f_past_valid_tx <= 1'b1;
|
f_past_valid_tx <= 1'b1;
|
|
|
Line 311... |
Line 302... |
|
|
// parameter TIMER_BITS = 10;
|
// parameter TIMER_BITS = 10;
|
// parameter [(TIMER_BITS-1):0] CLOCKS_PER_BAUD = 868;
|
// parameter [(TIMER_BITS-1):0] CLOCKS_PER_BAUD = 868;
|
// localparam TB = TIMER_BITS;
|
// localparam TB = TIMER_BITS;
|
|
|
assign f_tx_start = $anyseq;
|
|
always @(*)
|
always @(*)
|
if (f_tx_busy)
|
if (f_tx_busy)
|
assume(!f_tx_start);
|
assume(!f_tx_start);
|
|
|
initial f_tx_baud = 0;
|
initial f_tx_baud = 0;
|
Line 324... |
Line 314... |
f_tx_baud <= CLOCKS_PER_BAUD-1'b1;
|
f_tx_baud <= CLOCKS_PER_BAUD-1'b1;
|
else if (!f_tx_zbaud)
|
else if (!f_tx_zbaud)
|
f_tx_baud <= f_tx_baud - 1'b1;
|
f_tx_baud <= f_tx_baud - 1'b1;
|
|
|
always @(*)
|
always @(*)
|
`PHASE_ONE_ASSERT(f_tx_baud < CLOCKS_PER_BAUD);
|
`ASSERT(f_tx_baud < CLOCKS_PER_BAUD);
|
|
|
always @(*)
|
always @(*)
|
if (!f_tx_busy)
|
if (!f_tx_busy)
|
`PHASE_ONE_ASSERT(f_tx_baud == 0);
|
`ASSERT(f_tx_baud == 0);
|
|
|
assign f_tx_zbaud = (f_tx_baud == 0);
|
assign f_tx_zbaud = (f_tx_baud == 0);
|
|
|
// Pick some data to transmit
|
|
assign f_tx_data = $anyseq;
|
|
|
|
// But only if we aren't busy
|
// But only if we aren't busy
|
initial assume(f_tx_data == 0);
|
initial assume(f_tx_data == 0);
|
always @(posedge f_txclk)
|
always @(posedge f_txclk)
|
if ((!f_tx_zbaud)||(f_tx_busy)||(!f_tx_start))
|
if ((!f_tx_zbaud)||(f_tx_busy)||(!f_tx_start))
|
assume(f_tx_data == $past(f_tx_data));
|
assume(f_tx_data == $past(f_tx_data));
|
Line 369... |
Line 356... |
initial f_tx_busy = 1'b0;
|
initial f_tx_busy = 1'b0;
|
initial f_tx_reg = 0;
|
initial f_tx_reg = 0;
|
always @(posedge f_txclk)
|
always @(posedge f_txclk)
|
if (!f_tx_zbaud)
|
if (!f_tx_zbaud)
|
begin
|
begin
|
`PHASE_ONE_ASSERT(f_tx_busy);
|
`ASSERT(f_tx_busy);
|
end else begin
|
end else begin
|
f_tx_reg <= { 1'b0, f_tx_reg[9:1] };
|
f_tx_reg <= { 1'b0, f_tx_reg[9:1] };
|
if (f_tx_start)
|
if (f_tx_start)
|
f_tx_reg <= { 1'b1, f_tx_data, 1'b0 };
|
f_tx_reg <= { 1'b1, f_tx_data, 1'b0 };
|
end
|
end
|
Line 389... |
Line 376... |
|
|
//
|
//
|
// Tie the TX register to the TX data
|
// Tie the TX register to the TX data
|
always @(posedge f_txclk)
|
always @(posedge f_txclk)
|
if (f_tx_reg[9])
|
if (f_tx_reg[9])
|
`PHASE_ONE_ASSERT(f_tx_reg[8:0] == { f_tx_data, 1'b0 });
|
`ASSERT(f_tx_reg[8:0] == { f_tx_data, 1'b0 });
|
else if (f_tx_reg[8])
|
else if (f_tx_reg[8])
|
`PHASE_ONE_ASSERT(f_tx_reg[7:0] == f_tx_data[7:0] );
|
`ASSERT(f_tx_reg[7:0] == f_tx_data[7:0] );
|
else if (f_tx_reg[7])
|
else if (f_tx_reg[7])
|
`PHASE_ONE_ASSERT(f_tx_reg[6:0] == f_tx_data[7:1] );
|
`ASSERT(f_tx_reg[6:0] == f_tx_data[7:1] );
|
else if (f_tx_reg[6])
|
else if (f_tx_reg[6])
|
`PHASE_ONE_ASSERT(f_tx_reg[5:0] == f_tx_data[7:2] );
|
`ASSERT(f_tx_reg[5:0] == f_tx_data[7:2] );
|
else if (f_tx_reg[5])
|
else if (f_tx_reg[5])
|
`PHASE_ONE_ASSERT(f_tx_reg[4:0] == f_tx_data[7:3] );
|
`ASSERT(f_tx_reg[4:0] == f_tx_data[7:3] );
|
else if (f_tx_reg[4])
|
else if (f_tx_reg[4])
|
`PHASE_ONE_ASSERT(f_tx_reg[3:0] == f_tx_data[7:4] );
|
`ASSERT(f_tx_reg[3:0] == f_tx_data[7:4] );
|
else if (f_tx_reg[3])
|
else if (f_tx_reg[3])
|
`PHASE_ONE_ASSERT(f_tx_reg[2:0] == f_tx_data[7:5] );
|
`ASSERT(f_tx_reg[2:0] == f_tx_data[7:5] );
|
else if (f_tx_reg[2])
|
else if (f_tx_reg[2])
|
`PHASE_ONE_ASSERT(f_tx_reg[1:0] == f_tx_data[7:6] );
|
`ASSERT(f_tx_reg[1:0] == f_tx_data[7:6] );
|
else if (f_tx_reg[1])
|
else if (f_tx_reg[1])
|
`PHASE_ONE_ASSERT(f_tx_reg[0] == f_tx_data[7]);
|
`ASSERT(f_tx_reg[0] == f_tx_data[7]);
|
|
|
// Our counter since we start
|
// Our counter since we start
|
initial f_tx_count = 0;
|
initial f_tx_count = 0;
|
always @(posedge f_txclk)
|
always @(posedge f_txclk)
|
if (!f_tx_busy)
|
if (!f_tx_busy)
|
Line 428... |
Line 415... |
//
|
//
|
always @(posedge f_txclk)
|
always @(posedge f_txclk)
|
if (!f_tx_busy)
|
if (!f_tx_busy)
|
begin
|
begin
|
if ((!f_past_valid_tx)||(!$past(f_tx_busy)))
|
if ((!f_past_valid_tx)||(!$past(f_tx_busy)))
|
`PHASE_ONE_ASSERT(f_tx_count == 0);
|
`ASSERT(f_tx_count == 0);
|
end else if (f_tx_reg[9])
|
end else if (f_tx_reg[9])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
CLOCKS_PER_BAUD -1 -f_tx_baud);
|
CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else if (f_tx_reg[8])
|
else if (f_tx_reg[8])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
2 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
2 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else if (f_tx_reg[7])
|
else if (f_tx_reg[7])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
3 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
3 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else if (f_tx_reg[6])
|
else if (f_tx_reg[6])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
4 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
4 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else if (f_tx_reg[5])
|
else if (f_tx_reg[5])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
5 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
5 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else if (f_tx_reg[4])
|
else if (f_tx_reg[4])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
6 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
6 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else if (f_tx_reg[3])
|
else if (f_tx_reg[3])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
7 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
7 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else if (f_tx_reg[2])
|
else if (f_tx_reg[2])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
8 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
8 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else if (f_tx_reg[1])
|
else if (f_tx_reg[1])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
9 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
9 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else if (f_tx_reg[0])
|
else if (f_tx_reg[0])
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
10 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
10 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
else
|
else
|
`PHASE_ONE_ASSERT(f_tx_count ==
|
`ASSERT(f_tx_count ==
|
11 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
11 * CLOCKS_PER_BAUD -1 -f_tx_baud);
|
|
|
|
|
///////////////////////////////////////
|
///////////////////////////////////////
|
//
|
//
|
Line 480... |
Line 467... |
f_rx_count = (!ck_uart) ? (chg_counter+2) : 0;
|
f_rx_count = (!ck_uart) ? (chg_counter+2) : 0;
|
else
|
else
|
f_rx_count <= f_rx_count + 1'b1;
|
f_rx_count <= f_rx_count + 1'b1;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (state == 0)
|
if (state == 0)
|
`PHASE_ONE_ASSERT(f_rx_count
|
`ASSERT(f_rx_count
|
== half_baud + (CLOCKS_PER_BAUD-baud_counter));
|
== half_baud + (CLOCKS_PER_BAUD-baud_counter));
|
else if (state == 1)
|
else if (state == 1)
|
`PHASE_ONE_ASSERT(f_rx_count == half_baud + 2 * CLOCKS_PER_BAUD
|
`ASSERT(f_rx_count == half_baud + 2 * CLOCKS_PER_BAUD
|
- baud_counter);
|
- baud_counter);
|
else if (state == 2)
|
else if (state == 2)
|
`PHASE_ONE_ASSERT(f_rx_count == half_baud + 3 * CLOCKS_PER_BAUD
|
`ASSERT(f_rx_count == half_baud + 3 * CLOCKS_PER_BAUD
|
- baud_counter);
|
- baud_counter);
|
else if (state == 3)
|
else if (state == 3)
|
`PHASE_ONE_ASSERT(f_rx_count == half_baud + 4 * CLOCKS_PER_BAUD
|
`ASSERT(f_rx_count == half_baud + 4 * CLOCKS_PER_BAUD
|
- baud_counter);
|
- baud_counter);
|
else if (state == 4)
|
else if (state == 4)
|
`PHASE_ONE_ASSERT(f_rx_count == half_baud + 5 * CLOCKS_PER_BAUD
|
`ASSERT(f_rx_count == half_baud + 5 * CLOCKS_PER_BAUD
|
- baud_counter);
|
- baud_counter);
|
else if (state == 5)
|
else if (state == 5)
|
`PHASE_ONE_ASSERT(f_rx_count == half_baud + 6 * CLOCKS_PER_BAUD
|
`ASSERT(f_rx_count == half_baud + 6 * CLOCKS_PER_BAUD
|
- baud_counter);
|
- baud_counter);
|
else if (state == 6)
|
else if (state == 6)
|
`PHASE_ONE_ASSERT(f_rx_count == half_baud + 7 * CLOCKS_PER_BAUD
|
`ASSERT(f_rx_count == half_baud + 7 * CLOCKS_PER_BAUD
|
- baud_counter);
|
- baud_counter);
|
else if (state == 7)
|
else if (state == 7)
|
`PHASE_ONE_ASSERT(f_rx_count == half_baud + 8 * CLOCKS_PER_BAUD
|
`ASSERT(f_rx_count == half_baud + 8 * CLOCKS_PER_BAUD
|
- baud_counter);
|
- baud_counter);
|
else if (state == 8)
|
else if (state == 8)
|
`PHASE_ONE_ASSERT((f_rx_count == half_baud + 9 * CLOCKS_PER_BAUD
|
`ASSERT((f_rx_count == half_baud + 9 * CLOCKS_PER_BAUD
|
- baud_counter)
|
- baud_counter)
|
||(f_rx_count == half_baud + 10 * CLOCKS_PER_BAUD
|
||(f_rx_count == half_baud + 10 * CLOCKS_PER_BAUD
|
- baud_counter));
|
- baud_counter));
|
|
|
always @(*)
|
always @(*)
|
`PHASE_ONE_ASSERT( ((!zero_baud_counter)
|
`ASSERT( ((!zero_baud_counter)
|
&&(state == `RXUL_IDLE)
|
&&(state == `RXUL_IDLE)
|
&&(baud_counter == 0))
|
&&(baud_counter == 0))
|
||((zero_baud_counter)&&(baud_counter == 0))
|
||((zero_baud_counter)&&(baud_counter == 0))
|
||((!zero_baud_counter)&&(baud_counter != 0)));
|
||((!zero_baud_counter)&&(baud_counter != 0)));
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (!f_past_valid)
|
if (!f_past_valid)
|
`PHASE_ONE_ASSERT((state == `RXUL_IDLE)&&(baud_counter == 0)
|
`ASSERT((state == `RXUL_IDLE)&&(baud_counter == 0)
|
&&(zero_baud_counter));
|
&&(zero_baud_counter));
|
|
|
always @(*)
|
always @(*)
|
begin
|
begin
|
`PHASE_ONE_ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h2);
|
`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h2);
|
`PHASE_ONE_ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h4);
|
`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h4);
|
`PHASE_ONE_ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h5);
|
`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h5);
|
`PHASE_ONE_ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h6);
|
`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h6);
|
`PHASE_ONE_ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h9);
|
`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h9);
|
`PHASE_ONE_ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'ha);
|
`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'ha);
|
`PHASE_ONE_ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'hb);
|
`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'hb);
|
`PHASE_ONE_ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'hd);
|
`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'hd);
|
end
|
end
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if ((f_past_valid)&&($past(state) >= `RXUL_WAIT)&&($past(ck_uart)))
|
if ((f_past_valid)&&($past(state) >= `RXUL_WAIT)&&($past(ck_uart)))
|
`PHASE_ONE_ASSERT(state == `RXUL_IDLE);
|
`ASSERT(state == `RXUL_IDLE);
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if ((f_past_valid)&&($past(state) >= `RXUL_WAIT)
|
if ((f_past_valid)&&($past(state) >= `RXUL_WAIT)
|
&&(($past(state) != `RXUL_IDLE)||(state == `RXUL_IDLE)))
|
&&(($past(state) != `RXUL_IDLE)||(state == `RXUL_IDLE)))
|
`PHASE_ONE_ASSERT(zero_baud_counter);
|
`ASSERT(zero_baud_counter);
|
|
|
// Calculate an absolute value of the difference between the two baud
|
// Calculate an absolute value of the difference between the two baud
|
// clocks
|
// clocks
|
`ifdef PHASE_TWO
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if ((f_past_valid)&&($past(state)==`RXUL_IDLE)&&(state == `RXUL_IDLE))
|
if ((f_past_valid)&&($past(state)==`RXUL_IDLE)&&(state == `RXUL_IDLE))
|
begin
|
begin
|
`PHASE_TWO_ASSERT(($past(ck_uart))
|
`ASSERT(($past(ck_uart))
|
||(chg_counter <=
|
||(chg_counter <=
|
{ 1'b0, CLOCKS_PER_BAUD[(TB-1):1] }));
|
{ 1'b0, CLOCKS_PER_BAUD[(TB-1):1] }));
|
end
|
end
|
|
|
always @(posedge f_txclk)
|
always @(posedge f_txclk)
|
if (!f_past_valid_tx)
|
if (!f_past_valid_tx)
|
`PHASE_TWO_ASSERT((state == `RXUL_IDLE)&&(baud_counter == 0)
|
`ASSERT((state == `RXUL_IDLE)&&(baud_counter == 0)
|
&&(zero_baud_counter)&&(!f_tx_busy));
|
&&(zero_baud_counter)&&(!f_tx_busy));
|
|
|
wire [(TB+3):0] f_tx_count_two_clocks_ago;
|
wire [(TB+3):0] f_tx_count_two_clocks_ago;
|
assign f_tx_count_two_clocks_ago = f_tx_count - 2;
|
assign f_tx_count_two_clocks_ago = f_tx_count - 2;
|
always @(*)
|
always @(*)
|
Line 568... |
Line 554... |
else
|
else
|
f_baud_difference = f_rx_count - f_tx_count_two_clocks_ago;
|
f_baud_difference = f_rx_count - f_tx_count_two_clocks_ago;
|
|
|
localparam F_SYNC_DLY = 8;
|
localparam F_SYNC_DLY = 8;
|
|
|
wire [(TB+4+F_CKRES-1):0] f_sub_baud_difference;
|
reg [(TB+4+F_CKRES-1):0] f_sub_baud_difference;
|
reg [F_CKRES-1:0] ck_tx_clock;
|
reg [F_CKRES-1:0] ck_tx_clock;
|
reg [((F_SYNC_DLY-1)*F_CKRES)-1:0] q_tx_clock;
|
reg [((F_SYNC_DLY-1)*F_CKRES)-1:0] q_tx_clock;
|
reg [TB+3:0] ck_tx_count;
|
reg [TB+3:0] ck_tx_count;
|
reg [(F_SYNC_DLY-1)*(TB+4)-1:0] q_tx_count;
|
reg [(F_SYNC_DLY-1)*(TB+4)-1:0] q_tx_count;
|
initial q_tx_count = 0;
|
initial q_tx_count = 0;
|
Line 583... |
Line 569... |
{ ck_tx_clock, q_tx_clock } <= { q_tx_clock, f_tx_clock };
|
{ ck_tx_clock, q_tx_clock } <= { q_tx_clock, f_tx_clock };
|
always @($global_clock)
|
always @($global_clock)
|
{ ck_tx_count, q_tx_count } <= { q_tx_count, f_tx_count };
|
{ ck_tx_count, q_tx_count } <= { q_tx_count, f_tx_count };
|
|
|
|
|
wire [TB+4+F_CKRES-1:0] f_ck_tx_time, f_rx_time;
|
reg [TB+4+F_CKRES-1:0] f_ck_tx_time, f_rx_time;
|
always @(*)
|
always @(*)
|
f_ck_tx_time = { ck_tx_count, !ck_tx_clock[F_CKRES-1],
|
f_ck_tx_time = { ck_tx_count, !ck_tx_clock[F_CKRES-1],
|
ck_tx_clock[F_CKRES-2:0] };
|
ck_tx_clock[F_CKRES-2:0] };
|
always @(*)
|
always @(*)
|
f_rx_time = { f_rx_count, !f_rx_clock[1], f_rx_clock[0],
|
f_rx_time = { f_rx_count, !f_rx_clock[1], f_rx_clock[0],
|
{(F_CKRES-2){1'b0}} };
|
{(F_CKRES-2){1'b0}} };
|
|
|
wire [TB+4+F_CKRES-1:0] f_signed_difference;
|
reg [TB+4+F_CKRES-1:0] f_signed_difference;
|
always @(*)
|
always @(*)
|
f_signed_difference = f_ck_tx_time - f_rx_time;
|
f_signed_difference = f_ck_tx_time - f_rx_time;
|
|
|
always @(*)
|
always @(*)
|
if (f_signed_difference[TB+4+F_CKRES-1])
|
if (f_signed_difference[TB+4+F_CKRES-1])
|
Line 603... |
Line 589... |
else
|
else
|
f_sub_baud_difference = f_signed_difference;
|
f_sub_baud_difference = f_signed_difference;
|
|
|
always @($global_clock)
|
always @($global_clock)
|
if (state == `RXUL_WAIT)
|
if (state == `RXUL_WAIT)
|
`PHASE_TWO_ASSERT((!f_tx_busy)||(f_tx_reg[9:1] == 0));
|
`ASSERT((!f_tx_busy)||(f_tx_reg[9:1] == 0));
|
|
|
always @($global_clock)
|
always @($global_clock)
|
if (state == `RXUL_IDLE)
|
if (state == `RXUL_IDLE)
|
begin
|
begin
|
`PHASE_TWO_ASSERT((!f_tx_busy)||(f_tx_reg[9])||(f_tx_reg[9:1]==0));
|
`ASSERT((!f_tx_busy)||(f_tx_reg[9])||(f_tx_reg[9:1]==0));
|
if (!ck_uart)
|
if (!ck_uart)
|
;//`PHASE_TWO_ASSERT((f_rx_count < 4)||(f_sub_baud_difference <= ((CLOCKS_PER_BAUD<<F_CKRES)/20)));
|
;//`PHASE_TWO_ASSERT((f_rx_count < 4)||(f_sub_baud_difference <= ((CLOCKS_PER_BAUD<<F_CKRES)/20)));
|
else
|
else
|
`PHASE_TWO_ASSERT((f_tx_reg[9:1]==0)||(f_tx_count < (3 + CLOCKS_PER_BAUD/2)));
|
`ASSERT((f_tx_reg[9:1]==0)||(f_tx_count < (3 + CLOCKS_PER_BAUD/2)));
|
end else if (state == 0)
|
end else if (state == 0)
|
`PHASE_TWO_ASSERT(f_sub_baud_difference
|
`ASSERT(f_sub_baud_difference
|
<= 2 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
<= 2 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
else if (state == 1)
|
else if (state == 1)
|
`PHASE_TWO_ASSERT(f_sub_baud_difference
|
`ASSERT(f_sub_baud_difference
|
<= 3 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
<= 3 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
else if (state == 2)
|
else if (state == 2)
|
`PHASE_TWO_ASSERT(f_sub_baud_difference
|
`ASSERT(f_sub_baud_difference
|
<= 4 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
<= 4 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
else if (state == 3)
|
else if (state == 3)
|
`PHASE_TWO_ASSERT(f_sub_baud_difference
|
`ASSERT(f_sub_baud_difference
|
<= 5 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
<= 5 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
else if (state == 4)
|
else if (state == 4)
|
`PHASE_TWO_ASSERT(f_sub_baud_difference
|
`ASSERT(f_sub_baud_difference
|
<= 6 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
<= 6 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
else if (state == 5)
|
else if (state == 5)
|
`PHASE_TWO_ASSERT(f_sub_baud_difference
|
`ASSERT(f_sub_baud_difference
|
<= 7 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
<= 7 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
else if (state == 6)
|
else if (state == 6)
|
`PHASE_TWO_ASSERT(f_sub_baud_difference
|
`ASSERT(f_sub_baud_difference
|
<= 8 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
<= 8 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
else if (state == 7)
|
else if (state == 7)
|
`PHASE_TWO_ASSERT(f_sub_baud_difference
|
`ASSERT(f_sub_baud_difference
|
<= 9 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
<= 9 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
else if (state == 8)
|
else if (state == 8)
|
`PHASE_TWO_ASSERT(f_sub_baud_difference
|
`ASSERT(f_sub_baud_difference
|
<= 10 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
<= 10 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (o_wr)
|
if (o_wr)
|
`PHASE_TWO_ASSERT(o_data == $past(f_tx_data,4));
|
`ASSERT(o_data == $past(f_tx_data,4));
|
|
|
// always @(posedge i_clk)
|
// always @(posedge i_clk)
|
// if ((zero_baud_counter)&&(state != 4'hf)&&(CLOCKS_PER_BAUD > 6))
|
// if ((zero_baud_counter)&&(state != 4'hf)&&(CLOCKS_PER_BAUD > 6))
|
// assert(i_uart_rx == ck_uart);
|
// assert(i_uart_rx == ck_uart);
|
|
|
// Make sure the data register matches
|
// Make sure the data register matches
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
// if ((f_past_valid)&&(state != $past(state)))
|
// if ((f_past_valid)&&(state != $past(state)))
|
begin
|
begin
|
if (state == 4'h0)
|
if (state == 4'h0)
|
`PHASE_TWO_ASSERT(!data_reg[7]);
|
`ASSERT(!data_reg[7]);
|
|
|
if (state == 4'h1)
|
if (state == 4'h1)
|
`PHASE_TWO_ASSERT((data_reg[7]
|
`ASSERT((data_reg[7]
|
== $past(f_tx_data[0]))&&(!data_reg[6]));
|
== $past(f_tx_data[0]))&&(!data_reg[6]));
|
|
|
if (state == 4'h2)
|
if (state == 4'h2)
|
`PHASE_TWO_ASSERT(data_reg[7:6]
|
`ASSERT(data_reg[7:6]
|
== $past(f_tx_data[1:0]));
|
== $past(f_tx_data[1:0]));
|
|
|
if (state == 4'h3)
|
if (state == 4'h3)
|
`PHASE_TWO_ASSERT(data_reg[7:5] == $past(f_tx_data[2:0]));
|
`ASSERT(data_reg[7:5] == $past(f_tx_data[2:0]));
|
|
|
if (state == 4'h4)
|
if (state == 4'h4)
|
`PHASE_TWO_ASSERT(data_reg[7:4] == $past(f_tx_data[3:0]));
|
`ASSERT(data_reg[7:4] == $past(f_tx_data[3:0]));
|
|
|
if (state == 4'h5)
|
if (state == 4'h5)
|
`PHASE_TWO_ASSERT(data_reg[7:3] == $past(f_tx_data[4:0]));
|
`ASSERT(data_reg[7:3] == $past(f_tx_data[4:0]));
|
|
|
if (state == 4'h6)
|
if (state == 4'h6)
|
`PHASE_TWO_ASSERT(data_reg[7:2] == $past(f_tx_data[5:0]));
|
`ASSERT(data_reg[7:2] == $past(f_tx_data[5:0]));
|
|
|
if (state == 4'h7)
|
if (state == 4'h7)
|
`PHASE_TWO_ASSERT(data_reg[7:1] == $past(f_tx_data[6:0]));
|
`ASSERT(data_reg[7:1] == $past(f_tx_data[6:0]));
|
|
|
if (state == 4'h8)
|
if (state == 4'h8)
|
`PHASE_TWO_ASSERT(data_reg[7:0] == $past(f_tx_data[7:0]));
|
`ASSERT(data_reg[7:0] == $past(f_tx_data[7:0]));
|
end
|
end
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Cover properties
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
always @(posedge i_clk)
|
|
cover(o_wr); // Step 626, takes about 20mins
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
cover(o_wr);
|
begin
|
`endif
|
cover(!ck_uart);
|
|
cover((f_past_valid)&&($rose(ck_uart))); // 82
|
|
cover((zero_baud_counter)&&(state == `RXUL_BIT_ZERO)); // 110
|
|
cover((zero_baud_counter)&&(state == `RXUL_BIT_ONE)); // 174
|
|
cover((zero_baud_counter)&&(state == `RXUL_BIT_TWO)); // 238
|
|
cover((zero_baud_counter)&&(state == `RXUL_BIT_THREE));// 302
|
|
cover((zero_baud_counter)&&(state == `RXUL_BIT_FOUR)); // 366
|
|
cover((zero_baud_counter)&&(state == `RXUL_BIT_FIVE)); // 430
|
|
cover((zero_baud_counter)&&(state == `RXUL_BIT_SIX)); // 494
|
|
cover((zero_baud_counter)&&(state == `RXUL_BIT_SEVEN));// 558
|
|
cover((zero_baud_counter)&&(state == `RXUL_STOP)); // 622
|
|
cover((zero_baud_counter)&&(state == `RXUL_WAIT)); // 626
|
|
end
|
|
|
`endif
|
`endif
|
`ifdef FORMAL_VERILATOR
|
`ifdef FORMAL_VERILATOR
|
// FORMAL properties which can be tested via Verilator as well as
|
// FORMAL properties which can be tested via Verilator as well as
|
// Yosys FORMAL
|
// Yosys FORMAL
|
always @(*)
|
always @(*)
|