blob: 07fe83fc5a5c24fefa0c78e4b50e2871967f83df [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class uart_monitor extends uvm_monitor;
`uvm_component_utils(uart_monitor)
uart_agent_cfg cfg;
uart_agent_cov cov;
// Analysis port for the collected transfer.
uvm_analysis_port #(uart_item) tx_analysis_port;
uvm_analysis_port #(uart_item) rx_analysis_port;
`uvm_component_new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
tx_analysis_port = new("tx_analysis_port", this);
rx_analysis_port = new("rx_analysis_port", this);
endfunction
task run_phase(uvm_phase phase);
fork
collect_tx_data(phase);
collect_rx_data(phase);
join
endtask
virtual task collect_tx_data(uvm_phase phase);
uart_item item;
forever begin
if (cfg.vif.uart_tx === 1'b0 && cfg.en_tx_monitor == 1) begin
// 1 start + 8 data + 1 parity (if enabled) + 1 stop
cfg.vif.uart_tx_clk_pulses = 1 + 8 + cfg.en_parity + 1;
phase.raise_objection(this);
`uvm_info(`gtn, "raise_objection, TX starts", UVM_DEBUG)
item = uart_item::type_id::create("item");
// get the start bit
@(cfg.vif.mon_tx_mp.mon_tx_cb);
`uvm_info(`gtn, $sformatf("tx start bit %0b", cfg.vif.uart_tx), UVM_DEBUG)
item.start_bit = cfg.vif.uart_tx;
// get the data bits
for (int i = 0; i < 8; i++) begin
@(cfg.vif.mon_tx_mp.mon_tx_cb);
`uvm_info(`gtn, $sformatf("tx data bit[%0d] %0b", i, cfg.vif.uart_tx), UVM_DEBUG)
item.data[i] = cfg.vif.uart_tx;
end
// get the parity bit
if (cfg.vif.uart_tx_clk_pulses > 2) begin
@(cfg.vif.mon_tx_mp.mon_tx_cb);
`uvm_info(`gtn, $sformatf("tx parity bit %0b", cfg.vif.uart_tx), UVM_DEBUG)
item.parity = cfg.vif.uart_tx;
if (cfg.en_tx_checks && item.parity != `GET_PARITY(item.data, cfg.odd_parity)) begin
`uvm_error(`gtn, "Parity failed")
end
end
else item.parity = 1'b0;
// get the stop bit
@(cfg.vif.mon_tx_mp.mon_tx_cb);
`uvm_info(`gtn, $sformatf("tx stop bit %0b", cfg.vif.uart_tx), UVM_DEBUG)
item.stop_bit = cfg.vif.uart_tx;
// check stop bit
if (cfg.en_tx_checks && cfg.vif.uart_tx !== 1'b1) begin
`uvm_error(`gtn, "No stop bit when expected!")
end
`uvm_info(`gtn, $sformatf("collected uart tx txn:\n%0s", item.sprint()), UVM_HIGH)
tx_analysis_port.write(item);
// wait for uart_tx_clk_pulses==0, otherwise, it may affect next transaction
cfg.vif.wait_for_tx_idle();
if (cfg.en_cov) cov.uart_cg.sample(UartTx, item);
phase.drop_objection(this);
end else begin
@(cfg.vif.uart_tx);
end
end
endtask
virtual task collect_rx_data(uvm_phase phase);
uart_item item;
forever begin
if (cfg.vif.uart_rx === 1'b0 && cfg.en_rx_monitor == 1) begin
phase.raise_objection(this);
`uvm_info(`gtn, "raise_objection, RX starts", UVM_DEBUG)
item = uart_item::type_id::create("item");
cfg.vif.uart_rx_clk_pulses = 1 + 8 + cfg.en_parity + 1;;
// get the start bit
@(cfg.vif.mon_rx_mp.mon_rx_cb);
`uvm_info(`gtn, $sformatf("rx start bit %0b", cfg.vif.uart_rx), UVM_DEBUG)
item.start_bit = cfg.vif.uart_rx;
// get the data bits
for (int i = 0; i < 8; i++) begin
@(cfg.vif.mon_rx_mp.mon_rx_cb);
`uvm_info(`gtn, $sformatf("rx data bit[%0d] %0b", i, cfg.vif.uart_rx), UVM_DEBUG)
item.data[i] = cfg.vif.uart_rx;
end
// get the parity bit
if (cfg.vif.uart_rx_clk_pulses > 2) begin
@(cfg.vif.mon_rx_mp.mon_rx_cb);
`uvm_info(`gtn, $sformatf("rx parity bit %0b", cfg.vif.uart_rx), UVM_DEBUG)
item.parity = cfg.vif.uart_rx;
if (cfg.en_rx_checks && item.parity != `GET_PARITY(item.data, cfg.odd_parity)) begin
`uvm_error(`gtn, "Parity failed")
end
end
else item.parity = 1'b0;
// get the stop bit
@(cfg.vif.mon_rx_mp.mon_rx_cb);
`uvm_info(`gtn, $sformatf("rx stop bit %0b", cfg.vif.uart_rx), UVM_DEBUG)
item.stop_bit = cfg.vif.uart_rx;
// check stop bit
if (cfg.en_rx_checks && cfg.vif.uart_rx !== 1'b1) begin
`uvm_error(`gtn, "No stop bit when expected!")
end
`uvm_info(`gtn, $sformatf("collected uart rx txn:\n%0s", item.sprint()), UVM_HIGH)
rx_analysis_port.write(item);
// wait for uart_rx_clk_pulses==0, otherwise, it may affect next transaction
cfg.vif.wait_for_rx_idle();
if (cfg.en_cov) cov.uart_cg.sample(UartRx, item);
phase.drop_objection(this);
end else begin
@(cfg.vif.uart_rx);
end
end
endtask
endclass