Hi,
I coded an I2C memory, there is some deficits but without clocking block it works well. (Without Clocking Block
I added clocking block with posedge. (I gave scl from outside for some reasons but it is not important.)
Tests passed but there is a different situation in wave form. State changes before than expected. WITH Clocking Block
Driver Part
task reset();
@(`TOP_IF);
`TOP_IF.rst <= 1'b1;
`TOP_IF.newd <= 1'b0;
`TOP_IF.wr <= 1'b0;
`TOP_IF.wdata <= 0;
`TOP_IF.addr <= 0;
repeat (3) @(`TOP_IF);
`TOP_IF.rst <= 1'b0;
`uvm_info("DRV", "DRV: Reset Detected", UVM_NONE)
endtask
virtual task run_phase(uvm_phase phase);
reset();
`TOP_IF.rst <= 1'b0;
forever begin
seq_item_port.get_next_item(tr);
if(tr.wr)
begin
@(`TOP_IF);
`TOP_IF.newd <= 1'b1;
`TOP_IF.wr <= tr.wr;
`TOP_IF.wdata <= tr.wdata;
`TOP_IF.addr <= tr.addr;
@(`TOP_IF); ///@(posedge vif.scl_ref);
`TOP_IF.newd <= 1'b0;
@(`TOP_IF);//@(posedge vif.scl_ref);
wait(`TOP_IF.done);// where pos done state is new_data
`uvm_info("DRV", $sformatf("DRV: WRITE ---> tr.wr: %0d --- tr.addr: %0d --- tr.wdata: %0d", tr.wr, tr.addr, tr.wdata), UVM_NONE)
end
else
begin
@(`TOP_IF);
`TOP_IF.newd <= 1'b1;
`TOP_IF.wr <= tr.wr;
//vif.wdata <= tr.wdata;
`TOP_IF.addr <= tr.addr;
@(`TOP_IF);//@(posedge vif.scl_ref);
`TOP_IF.newd <= 1'b0;
@(`TOP_IF);//@(posedge vif.scl_ref);
tr.rdata = `TOP_IF.rdata;
`uvm_info("DRV", $sformatf("DRV: %0d. READ ---> tr.wr: %0d --- tr.addr: %0d --- tr.rdata: %0d", count_read, tr.wr, tr.addr, tr.rdata), UVM_NONE)
count_read = count_read + 1;
end
seq_item_port.item_done();
end
endtask
Unexpected State
always@(posedge scl_ref, posedge rst)
begin
if(rst)
begin
rdata <= 0;
done <= 1'b0;
sdat <= 1'b1; // sdat and sclt is '1' in default
sclt <= 1'b1; // sdat and sclt is '1' in default
sda_en <= 1'b1; // sda_en is '1' in default
ack_en <= 1'b0; // ack_en is '1' in default
ackt <= 1'b0;
addrt <= 0;
wdata_reg <= 0;
rdata_reg <= 0;
end
else
begin
$monitor("[%0t] monitor for scl_ref posedge: newd == %0b -- 1'b1 and state will be 'wstart' in the next clock. ", $time(), newd);
//$monitor("[%0t] monitor for scl_ref posedge: state == %0d", $time(), state);
case(state)
new_data: begin
rdata <= 0;
done <= 1'b0;
sdat <= 1'b1; // sdat and sclt is '1' in default
sclt <= 1'b1; // sdat and sclt is '1' in default
sda_en <= 1'b1; // sda_en is '1' in default
ack_en <= 1'b0; // ack_en is '1' in default
ackt <= 1'b0;
addrt <= 0;
wdata_reg <= 0;
rdata_reg <= 0;
if(newd == 1'b1) // ----------> It changes unexpectedly.
begin
state <= wstart;
$display("[%0t] newd == %0b -- 1'b1 and state will be 'wstart' in the next clock. ", $time(), newd);
//$monitor("[%0t] monitor: newd == %0b -- 1'b1 and state will be 'wstart' in the next clock. ", $time(), newd);
//$strobe("[%0t] strobe: newd == %0b -- 1'b1 and state will be 'wstart' in the next clock. ", $time(), newd);
end
else
begin
state <= new_data;
end
end
I supposed state=2 should be 1 clock later since it is dependent on becoming of newd == 1’b1 with @(posedge scl_ref)
I tried different simulators on EDAPLAYGROUND and I used Xilinx 2022.
I used like @(clocking CB) in order not to violate something.
This is my interface at the bottom of design.
interface i2c_if;
logic clk;
logic scl_ref;
logic rst;
logic newd;
logic wr;
logic [7:0] wdata;
logic [6:0] addr;
logic [7:0] rdata;
logic done;
clocking top_cb @(posedge scl_ref); // according to testbench
default input #1step output #3ns;
output rst;
output newd;
output wr;
output wdata;
output addr;
input rdata;
input done;
endclocking
clocking mon_cb @(posedge scl_ref); // according to monitor
default input #1step; // --------------------------------> Monitor should only have an input skew, NO output skew;
input rst;
input newd;
input wr;
input wdata;
input addr;
input rdata;
input done;
endclocking
modport top_mp(clocking top_cb);
modport mon_mp(clocking mon_cb);
endinterface
Can anybody explain why?