How to write the monitor logic to control the sequential write and combination read?

Protocol description :-
•MCLK - Clock
•RESET - Reset
•PER_EN: when this signal is active, read access are executed during the current MCLK cycle while write access will be executed with the next MCLK rising edge. Note that this signal is HIGH ACTIVE.

• PER_ADDR: peripheral register address of the 16 bit word which is going to be accessed. It is to be noted that a 14 bit address will always be provided from the openMSP430 to the peripheral in order to accommodate the biggest possible PER_SIZE Verilog configuration option (i.e. 32kB as opposed to 512B by default). Note: in order to calculate the core logical address from the peripheral register physical address, the formula goes as following: LOGICAL@=2*PHYSICAL@

• PER_DOUT: the peripheral output word will be updated with every valid read/write access, it will be set to 0 otherwise.

• PER_WE: this signal selects which byte should be written during a valid access. PER_WE[0] will activate a write on the lower byte, PER_WE[1] a write on the upper byte. Note that these signals are HIGH ACTIVE.

• PER_DIN: the peripheral input word will be written with the valid write access according to the PER_WE value.

→ How to write the sampling logic to control the sequential write and combination read ?
I tried to write below code but i show that last transaction is not being sampled by the monitor and testcase completes without capturing that even i used the set_drain_time of uvm method to add some delay for completion but i feel there is some mistake in the monitor logic so i wanted to correct that.

  1. Driver CODE
    task get_and_drive(uvm_phase phase);
    bit pkt_drive_pending;
    bit got_item_from_seqr;
    uvm_info(get_name(),"get_and_drive started",UVM_HIGH); fork : MAIN_FORK begin : ASYNC_RESET_CHECK uvm_info(get_name(),“waiting for async reset”,UVM_HIGH);
    @(posedge p_vif.puc_reset);
    drive_reset_signals();
    if (pkt_drive_pending && got_item_from_seqr) begin
    seq_item_port.item_done();
    phase.drop_objection(this);
    end
    end : ASYNC_RESET_CHECK
    begin : DRIVE_DET_THREAD
    uvm_info(get_name(),"Waiting for sequence item",UVM_HIGH); seq_item_port.get_next_item(req); got_item_from_seqr = 1'b1; uvm_info(get_name(),$psprintf("Drive got item from sequencer : %s ",req.sprint()),UVM_HIGH);
    phase.raise_objection(this);
    // flag to monitor packet driving in progress
    pkt_drive_pending = 1’b1;
    if(req.rw_nop == READ) begin
    read_transfer(req);
    end
    else if (req.rw_nop == WRITE_LO || req.rw_nop == WRITE_HI || req.rw_nop == WRITE_WO) begin
    write_transfer(req);
    end
    else if (req.rw_nop == NOP) begin
    nop_transfer(req);
    end
    else
    uvm_error (get_type_name(), $sformatf(" Transfer type not supported")) pkt_drive_pending = 1'b0; repeat(req.clk_dly) begin @(posedge p_vif.MCLK); uvm_info(get_name(),“asserted delay cylce”,UVM_HIGH);
    end
    seq_item_port.item_done();
    got_item_from_seqr = 1’b0;
    phase.drop_objection(this);
    end : DRIVE_DET_THREAD
    join_any
    disable fork;
    wait(p_vif.puc_reset ==0);
    //@(negedge p_vif.puc_reset && p_vif.MCLK);
    `uvm_info(get_name(),“get_and_drive completed”,UVM_HIGH);
    endtask : get_and_drive
  2. Monitor code
    virtual task main_phase(uvm_phase phase);
    super.reset_phase(phase);
    while(1) begin
    uvm_info(get_type_name(), $psprintf("Monitor collect transfer"), UVM_NONE) collect_transaction(phase); end endtask task collect_transaction(uvm_phase phase); bit pkt_sample_pending; fork : MAIN_FORK begin uvm_info(“MONITOR_WAIT_ASYNC_RESET”,“waiting for async reset”,UVM_HIGH);
    @(posedge p_vif.puc_reset);
    uvm_info("MONITOR_ASYNC_RESET_DETECTED","async reset detected",UVM_HIGH); if(pkt_sample_pending == 1'b1)begin phase.drop_objection(this); end uvm_info(get_full_name(),“Detected Reset, stopping monitoring of data”,UVM_NONE)
    end
    begin
    @(posedge p_vif.MCLK);
    phase.raise_objection(this);
    pkt_sample_pending =1’b1;
    if (p_vif.per_en == 1’b1 && p_vif.per_wen != 2’b00) begin
    rcv_pkt.per_addr = p_vif.per_addr;
    rcv_pkt.per_din = p_vif.per_din;
    if(p_vif.per_wen == 2’b01) begin
    rcv_pkt.rw_nop = WRITE_LO;
    end
    else if (p_vif.per_wen == 2’b10) begin
    rcv_pkt.rw_nop = WRITE_HI;
    end
    else if (p_vif.per_wen == 2’b11) begin
    rcv_pkt.rw_nop = WRITE_WO;
    end
    uvm_info(get_type_name(), $psprintf("Monitor WRITE PKT \n%s", rcv_pkt.sprint()), UVM_HIGH) end else if (p_vif.per_en == 1'b1 && p_vif.per_wen == 2'b00) begin rcv_pkt.per_addr = p_vif.per_addr; uvm_info(get_type_name(), $psprintf(“Monitor READ PKT \n%s”, rcv_pkt.sprint()), UVM_HIGH)
    p_vif.per_dout <= rcv_pkt.per_dout;
    rcv_pkt.rw_nop = READ;
    end
    else begin
    if(nop_check_enable == 1’b0) begin
    rcv_pkt.per_addr = p_vif.per_addr;
    rcv_pkt.per_dout = p_vif.per_dout;
    rcv_pkt.per_din = p_vif.per_din;
    rcv_pkt.rw_nop = NOP;
    end
    end
    `uvm_info(get_type_name(), $psprintf(“Monitor \n%s”, rcv_pkt.sprint()), UVM_NONE)
    cov_collect_port.write(rcv_pkt);
    pkt_sample_pending =1’b0;
    phase.drop_objection(this);
    end
    join_any
    disable fork;
    wait(p_vif.puc_reset == 0);
    endtask
  3. simulation Result
    UVM_INFO peripheral_driver.sv(49) @ 30: uvm_test_top.env.peripheral_agnt.driver [uvm_test_top.env.peripheral_agnt.driver] in main_phase
    UVM_INFO peripheral_monitor.sv(64) @ 30: uvm_test_top.env.peripheral_agnt.monitor [peripheral_monitor] Monitor collect transfer
    UVM_INFO peripheral_monitor.sv(129) @ 35: uvm_test_top.env.peripheral_agnt.monitor [peripheral_monitor] Monitor

Name Type Size Value

rcv_pkt peripheral_transfer - @651
rw_nop direction_enum 3 NOP
per_addr integral 15 'h0
per_din integral 16 'h0
per_dout integral 16 'h0

UVM_INFO peripheral_monitor.sv(64) @ 35: uvm_test_top.env.peripheral_agnt.monitor [peripheral_monitor] Monitor collect transfer
UVM_INFO peripheral_driver.sv(147) @ 35: uvm_test_top.env.peripheral_agnt.driver [peripheral_driver] Driving

Name Type Size Value

req peripheral_transfer - @676
rw_nop direction_enum 3 WRITE_WO
per_addr integral 15 'h3
per_din integral 16 'h35bd
per_dout integral 16 'h0
begin_time time 64 30
depth int 32 'd3
parent sequence (name) string 6 wr_seq
parent sequence (full name) string 53 uvm_test_top.env.peripheral_agnt.sequencer.seq.wr_seq
sequencer string 42 uvm_test_top.env.peripheral_agnt.sequencer

UVM_INFO peripheral_monitor.sv(129) @ 45: uvm_test_top.env.peripheral_agnt.monitor [peripheral_monitor] Monitor

Name Type Size Value

rcv_pkt peripheral_transfer - @651
rw_nop direction_enum 3 WRITE_WO
per_addr integral 15 'h3
per_din integral 16 'h35bd
per_dout integral 16 'h0

UVM_INFO peripheral_monitor.sv(64) @ 45: uvm_test_top.env.peripheral_agnt.monitor [peripheral_monitor] Monitor collect transfer
UVM_INFO peripheral_driver.sv(156) @ 45: uvm_test_top.env.peripheral_agnt.driver [peripheral_driver] Driving

Name Type Size Value

req peripheral_transfer - @701
rw_nop direction_enum 3 NOP
per_addr integral 15 'h3485
per_din integral 16 'h744d
per_dout integral 16 'h0
begin_time time 64 35
depth int 32 'd3
parent sequence (name) string 7 nop_seq
parent sequence (full name) string 54 uvm_test_top.env.peripheral_agnt.sequencer.seq.nop_seq
sequencer string 42 uvm_test_top.env.peripheral_agnt.sequencer

45mem write xxxx
UVM_INFO peripheral_monitor.sv(129) @ 55: uvm_test_top.env.peripheral_agnt.monitor [peripheral_monitor] Monitor

Name Type Size Value

rcv_pkt peripheral_transfer - @651
rw_nop direction_enum 3 NOP
per_addr integral 15 'h3485
per_din integral 16 'h744d
per_dout integral 16 'h0

UVM_INFO peripheral_monitor.sv(64) @ 55: uvm_test_top.env.peripheral_agnt.monitor [peripheral_monitor] Monitor collect transfer
UVM_INFO peripheral_driver.sv(125) @ 55: uvm_test_top.env.peripheral_agnt.driver [peripheral_driver] Driving

Name Type Size Value

req peripheral_transfer - @709
rw_nop direction_enum 3 READ
per_addr integral 15 'h3
per_din integral 16 'h2aa1
per_dout integral 16 'h0
begin_time time 64 45
depth int 32 'd3
parent sequence (name) string 6 rd_seq
parent sequence (full name) string 53 uvm_test_top.env.peripheral_agnt.sequencer.seq.rd_seq
sequencer string 42 uvm_test_top.env.peripheral_agnt.sequencer

55mem read 35bd
UVM_INFO /apps/vcsmx/vcs/P-2019.06-1//etc/uvm-1.1/src/base/uvm_objection.svh(1273) @ 155: reporter [TEST_DONE] ‘run’ phase is ready to proceed to the ‘extract’ phase
UVM_INFO per_base_test.sv(50) @ 155: uvm_test_top [per_wr_rd_test] ---------------------------------------
UVM_INFO per_base_test.sv(51) @ 155: uvm_test_top [per_wr_rd_test] ---- TEST PASS ----
UVM_INFO per_base_test.sv(52) @ 155: uvm_test_top [per_wr_rd_test] ---------------------------------------

MEMORY DUT code
// Write data to Memory
always @(posedge clk)
if (per_en)
if(per_wen) begin
mem[per_addr] <= per_din;
$display($time ,“mem write %0h”, mem[per_addr]);
end
// Read data from memory
always @(per_en or per_wen)
if (per_en)
if(!per_wen) begin
per_dout = mem[per_addr];
$display($time ,“mem read %0h”, per_dout);
end