blob: 5ca1813457864eddf511398005a133ef55866444 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: 2021 , Dinesh Annayya
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Modified by Dinesh Annayya <dinesha@opencores.org>
//
`timescale 1ns/1ps
module uart_agent (
mclk,
txd,
rxd
);
input mclk;
output txd;
input rxd;
event uart_read_done, uart_write_done;
event error_detected,uart_parity_error, uart_stop_error1, uart_stop_error2;
event uart_timeout_error;
event abort;
reg [15:0] rx_count;
reg [15:0] tx_count;
reg [15:0] par_err_count;
reg [15:0] stop_err1_cnt;
reg [15:0] stop_err2_cnt;
reg [15:0] timeout_err_cnt;
reg [15:0] err_cnt;
reg uart_rxenb; // uart rx enable
reg txd, read, write;
wire uart_rx_clk;
reg uart_clk;
reg stop_err_check;
integer timeout_count;
integer data_bit_number;
reg [15:0] clk_count;
reg debug_mode;
reg error_ind; // 1 indicate error
initial
begin
uart_rxenb = 0;
debug_mode = 1; // Keep in debug mode and enable display
txd = 1'b1;
uart_clk = 0;
clk_count = 0;
stop_err_check = 0;
error_ind = 0;
end
always @(posedge mclk)
begin
if (clk_count == 'h0) begin
uart_clk = ~uart_clk;
clk_count = control_setup.divisor;
end else begin
clk_count = clk_count - 1;
end
end
assign uart_rx_clk = uart_clk;
always @(posedge mclk)
begin
if(uart_rxenb) begin
timeout_count = timeout_count + 1;
if (timeout_count >= (control_setup.maxtime * 16)) begin
timeout_count = 0;
uart_rxenb = 0;
-> abort;
end
end else begin
timeout_count = 0;
end
end
always @uart_read_done
rx_count = rx_count + 1;
always @uart_write_done
tx_count = tx_count + 1;
always @uart_parity_error begin
error_ind = 1;
par_err_count = par_err_count + 1;
end
always @uart_stop_error1 begin
error_ind = 1;
stop_err1_cnt = stop_err1_cnt + 1;
end
always @uart_stop_error2 begin
error_ind = 1;
stop_err2_cnt = stop_err2_cnt + 1;
end
always @uart_timeout_error begin
error_ind = 1;
timeout_err_cnt = timeout_err_cnt + 1;
end
always @error_detected begin
error_ind = 1;
err_cnt = err_cnt + 1;
end
////////////////////////////////////////////////////////////////////////////////
task uart_init;
begin
uart_rxenb = 0;
read = 0;
write = 0;
tx_count = 0;
rx_count = 0;
stop_err_check = 0;
par_err_count = 0;
stop_err1_cnt = 0;
stop_err2_cnt = 0;
timeout_err_cnt = 0;
err_cnt = 0;
clk_count = 0;
end
endtask
////////////////////////////////////////////////////////////////////////////////
task read_char_chk;
input expected_data;
integer i;
reg [7:0] expected_data;
reg [7:0] data;
reg parity;
begin
data = 8'h0;
parity = 1;
timeout_count = 0;
uart_rxenb = 1;
fork
begin : loop_1
@(abort)
if(debug_mode)
$display ("%m: >>>>> Exceed time limit, uart no responce.\n");
->uart_timeout_error;
disable loop_2;
end
begin : loop_2
// start cycle
@(negedge rxd)
disable loop_1;
read = 1;
// data cycle
@(posedge uart_rx_clk);
for (i = 0; i < data_bit_number; i = i + 1)
begin
@(posedge uart_rx_clk)
data[i] = rxd;
parity = parity ^ rxd;
end
// parity cycle
if(control_setup.parity_en)
begin
@(posedge uart_rx_clk);
if ((control_setup.even_odd_parity && (rxd == parity)) ||
(!control_setup.even_odd_parity && (rxd != parity)))
begin
$display ("%m: >>>>> Parity Error");
-> error_detected;
-> uart_parity_error;
end
end
// stop cycle 1
@(posedge uart_rx_clk);
if (!rxd)
begin
$display ("%m: >>>>> Stop signal 1 Error");
-> error_detected;
-> uart_stop_error1;
end
// stop cycle 2
if (control_setup.stop_bit_number)
begin
@(posedge uart_rx_clk); // stop cycle 2
if (!rxd)
begin
$display ("%m: >>>>> Stop signal 2 Error");
-> error_detected;
-> uart_stop_error2;
end
end
read = 0;
-> uart_read_done;
if (expected_data != data)
begin
$display ("%m: Error! Data return is %h, expecting %h", data, expected_data);
-> error_detected;
end
else begin
if(debug_mode)
$display ("%m: Data match %h", expected_data);
end
if(debug_mode)
$display ("%m:... Read Data from UART done cnt :%d...",rx_count +1);
end
join
uart_rxenb = 0;
end
endtask
////////////////////////////////////////////////////////////////////////////////
task read_char2;
output [7:0] rxd_data;
output timeout; // 1-> timeout
integer j;
reg [7:0] rxd_data;
reg [7:0] data;
reg parity;
begin
data = 8'h0;
parity = 1;
timeout_count = 0;
timeout = 0;
uart_rxenb = 1;
fork
begin
@(abort)
//$display (">>>>> Exceed time limit, uart no responce.\n");
//->uart_timeout_error;
timeout = 1;
end
begin
// start cycle
@(negedge rxd)
read = 1;
// data cycle
@(posedge uart_rx_clk );
for (j = 0; j < data_bit_number; j = j + 1)
begin
@(posedge uart_rx_clk)
data[j] = rxd;
parity = parity ^ rxd;
end
// parity cycle
if(control_setup.parity_en)
begin
@(posedge uart_rx_clk);
if ((control_setup.even_odd_parity && (rxd == parity)) ||
(!control_setup.even_odd_parity && (rxd != parity)))
begin
$display (">>>>> Parity Error");
-> error_detected;
-> uart_parity_error;
end
end
// stop cycle 1
@(posedge uart_rx_clk);
if (!rxd)
begin
$display (">>>>> Stop signal 1 Error");
-> error_detected;
-> uart_stop_error1;
end
// stop cycle 2
if (control_setup.stop_bit_number)
begin
@(posedge uart_rx_clk); // stop cycle 2
if (!rxd)
begin
$display (">>>>> Stop signal 2 Error");
-> error_detected;
-> uart_stop_error2;
end
end
read = 0;
-> uart_read_done;
// $display ("(%m) Received Data %c", data);
// $display ("... Read Data from UART done cnt :%d...",rx_count +1);
$write ("%c",data);
rxd_data = data;
end
join_any
disable fork; //disable pending fork activity
uart_rxenb = 0;
end
endtask
////////////////////////////////////////////////////////////////////////////////
task read_char;
output [7:0] rxd_data;
output timeout; // 1-> timeout
reg [7:0] rxd_data;
integer i;
reg [7:0] expected_data;
reg [7:0] data;
reg parity;
begin
data = 8'h0;
parity = 1;
timeout_count = 0;
timeout = 0;
uart_rxenb = 1;
fork
begin : loop_1
@(abort)
if(debug_mode)
$display ("%m: >>>>> Exceed time limit, uart no responce.\n");
timeout = 1;
->uart_timeout_error;
disable loop_2;
end
begin : loop_2
// start cycle
@(negedge rxd)
disable loop_1;
read = 1;
// data cycle
@(posedge uart_rx_clk);
for (i = 0; i < data_bit_number; i = i + 1)
begin
@(posedge uart_rx_clk)
data[i] = rxd;
parity = parity ^ rxd;
end
// parity cycle
if(control_setup.parity_en)
begin
@(posedge uart_rx_clk);
if ((control_setup.even_odd_parity && (rxd == parity)) ||
(!control_setup.even_odd_parity && (rxd != parity)))
begin
$display ("%m: >>>>> Parity Error");
-> error_detected;
-> uart_parity_error;
end
end
// stop cycle 1
@(posedge uart_rx_clk);
if (!rxd)
begin
$display ("%m: >>>>> Stop signal 1 Error");
-> error_detected;
-> uart_stop_error1;
end
// stop cycle 2
if (control_setup.stop_bit_number)
begin
@(posedge uart_rx_clk); // stop cycle 2
if (!rxd)
begin
$display ("%m: >>>>> Stop signal 2 Error");
-> error_detected;
-> uart_stop_error2;
end
end
read = 0;
-> uart_read_done;
rxd_data = data;
if(debug_mode) begin
$display ("%m: Received Data %h", rxd_data);
$display ("%m:... Read Data from UART done cnt :%d...",rx_count +1);
end
end
join
uart_rxenb = 0;
end
endtask
// Read Task without Timeout
task read_char3;
output [7:0] rxd_data;
reg [7:0] rxd_data;
integer i;
reg [7:0] data;
reg parity;
begin
data = 8'h0;
parity = 1;
uart_rxenb = 1;
fork
begin : loop_2
// start cycle
@(negedge rxd)
read = 1;
// data cycle
@(posedge uart_rx_clk);
for (i = 0; i < data_bit_number; i = i + 1)
begin
@(posedge uart_rx_clk)
data[i] = rxd;
parity = parity ^ rxd;
end
// parity cycle
if(control_setup.parity_en)
begin
@(posedge uart_rx_clk);
if ((control_setup.even_odd_parity && (rxd == parity)) ||
(!control_setup.even_odd_parity && (rxd != parity)))
begin
$display ("%m: >>>>> Parity Error");
-> error_detected;
-> uart_parity_error;
end
end
// stop cycle 1
@(posedge uart_rx_clk);
if (!rxd)
begin
$display ("%m: >>>>> Stop signal 1 Error");
-> error_detected;
-> uart_stop_error1;
end
// stop cycle 2
if (control_setup.stop_bit_number)
begin
@(posedge uart_rx_clk); // stop cycle 2
if (!rxd)
begin
$display ("%m: >>>>> Stop signal 2 Error");
-> error_detected;
-> uart_stop_error2;
end
end
read = 0;
-> uart_read_done;
rxd_data = data;
end
join
uart_rxenb = 0;
end
endtask
////////////////////////////////////////////////////////////////////////////////
task write_char;
input [7:0] data;
integer i;
reg parity; // 0: odd parity, 1: even parity
begin
parity = #1 1;
// start cycle
@(posedge uart_clk)
begin
txd = #1 0;
write = #1 1;
end
// data cycle
begin
for (i = 0; i < data_bit_number; i = i + 1)
begin
@(posedge uart_clk)
txd = #1 data[i];
parity = parity ^ data[i];
end
end
// parity cycle
if (control_setup.parity_en)
begin
@(posedge uart_clk)
txd = #1
// control_setup.stick_parity ? ~control_setup.even_odd_parity :
control_setup.even_odd_parity ? !parity : parity;
end
// stop cycle 1
@(posedge uart_clk)
txd = #1 stop_err_check ? 0 : 1;
// stop cycle 2
@(posedge uart_clk);
txd = #1 1;
if (data_bit_number == 5)
@(negedge uart_clk);
else if (control_setup.stop_bit_number)
@(posedge uart_clk);
write = #1 0;
if(debug_mode)
$display ("%m:... Write data %h to UART done cnt : %d ...\n", data,tx_count+1);
else
$write ("%c",data);
-> uart_write_done;
end
endtask
////////////////////////////////////////////////////////////////////////////////
task control_setup;
input [1:0] data_bit_set;
input stop_bit_number;
input parity_en;
input even_odd_parity;
input stick_parity;
input [15:0] maxtime;
input [15:0] divisor;
begin
clk_count = divisor;
data_bit_number = data_bit_set + 5;
end
endtask
////////////////////////////////////////////////////////////////////////////////
task report_status;
output [15:0] rx_nu;
output [15:0] tx_nu;
begin
$display ("-------------------- UART Reporting Configuration --------------------");
$display (" Data bit number setting is : %0d", data_bit_number);
$display (" Stop bit number setting is : %0d", control_setup.stop_bit_number + 1);
$display (" Divisor of Uart clock is : %0d", control_setup.divisor);
if (control_setup.parity_en)
$display (" Parity is enable");
else
$display (" Parity is disable");
if (control_setup.even_odd_parity)
$display (" Even parity setting");
else
$display (" Odd parity setting");
$display ("-----------------------------------------------------------------");
$display ("-------------------- Reporting Status --------------------\n");
$display (" Number of character received is : %d", rx_count);
$display (" Number of character sent is : %d", tx_count);
$display (" Number of parity error rxd is : %d", par_err_count);
$display (" Number of stop1 error rxd is : %d", stop_err1_cnt);
$display (" Number of stop2 error rxd is : %d", stop_err2_cnt);
$display (" Number of timeout error is : %d", timeout_err_cnt);
$display (" Number of error is : %d", err_cnt);
$display ("-----------------------------------------------------------------");
rx_nu = rx_count;
tx_nu = tx_count;
end
endtask
////////////////////////////////////////////////////////////////////////////////
endmodule