在开始新的内容之前想强调一下上篇文章中的tvip_axi_payload_store类,它主要是其到一个item中间缓存的作用,基于此,内部会有一些地址、数据、响应的队列,除此以外内部还定义了一些函数;
上篇文章分析axi-vip的master driver和item,接下来继续分析monitor的部分,先看第一个大类,tvip_axi_monitor_base,后续的其他monitor都是继承与他的。
整体框架也是类似于driver的框架:
protected task main();
fork
address_monitor_thread();
write_data_monitor_thread();
response_mointor_thread();
join
endtask
第一个任务,address_monitor_thread任务,具体代码如下:
protected task address_monitor_thread();
tvip_axi_item item;
forever begin
wait_for_address_valid();
sample_address(item);
wait_for_address_ready();
finish_address(item);
end
endtask
wait_for_address_valid任务主要是等aw通道或者ar通道的valid信号;wait_for_address_ready任务主要是等aw通道或者ar通道的ready信号;finish_address任务主要执行end_address任务和将item赋值为null的任务,对于end_address来说,主要做的是往端口里送数据,主要任务如下:
task end_address(tvip_axi_item item);
super.end_address(item);
address_item_port.write(item);
if (item.request_ended()) begin
request_item_port.write(item);
end
endtask
下面重点分析sample_address任务:
需要注意的是,这里分析需要把sample address任务和write_data_monitor_thread任务中的get_write_data_store任务一起分析。两个任务之间的信息交互是通过write_data_store[0][$]和write_data_store[1][$]两个队列进行交互的,整体结构如下:
protected virtual task sample_address(ref tvip_axi_item item);
tvip_axi_payload_store store;
if (is_write_component() && (write_data_stores[1].size() > 0)) begin
store = write_data_stores[1].pop_front();
item = store.item;
end
if (item == null) begin
item = create_monitor_item();
store = tvip_axi_payload_store::create(item);
if (is_write_component()) begin
write_data_stores[0].push_back(store);
end
end
item.access_type = (is_write_component()) ? TVIP_AXI_WRITE_ACCESS : TVIP_AXI_READ_ACCESS;
item.id = get_address_id();
item.address = get_address();
item.burst_length = get_burst_length();
item.burst_size = get_burst_size();
item.burst_type = get_burst_type();
item.protection = get_protection();
item.qos = get_qos();
begin_address(item);
response_stores[item.id].push_back(store);
endtask
接下来看write_data_monitor_thread,整个任务主要执行的内容就是:(1)等写数据的valid(2)store为null的时候,拿store,也就是前面框架图中的任务(3)等ready信号(4)采集写数据。
get_write_data_store任务主要执行的内容如下(也就是语句 store = get_write_data_store()):
protected function tvip_axi_payload_store get_write_data_store();
if (write_data_stores[0].size() > 0) begin
return write_data_stores[0].pop_front();
end
else begin
tvip_axi_item item;
tvip_axi_payload_store store;
item = create_monitor_item();
store = tvip_axi_payload_store::create(item);
write_data_stores[1].push_back(store);
return store;
end
endfunction
采集store的任务,sample_write_data(store),如下:
protected virtual task sample_write_data(ref tvip_axi_payload_store store);
store.store_write_data(get_write_data(), get_strobe());
if (get_write_data_last()) begin
store.pack_write_data();
end_write_data(store.item);
store = null;
end
endtask
其中end_write_data就是相当于从通道发送store中的item给别的组件。
最后看response_mointor_thread线程,这个线程和driver中的关于response的线程是类似的,但是需要注意这里的部分需要和sample address任务中的第七点任务(框图中的第七点)对应,框图中的第七点任务表示的是:
response_stores[item.id].push_back(store);
接下来看response_mointor_thread线程的整体任务是:
protected task response_mointor_thread();
bit busy;
tvip_axi_id id;
tvip_axi_id current_id;
forever begin
wait_for_response_valid();
id = get_response_id();
if ((!busy) || (id != current_id)) begin
if (is_valid_response(id)) begin
busy = 1;
current_id = id;
if (!response_stores[current_id][0].item.response_began()) begin
begin_response(response_stores[current_id][0].item);
end
end
else begin
busy = 0;
`uvm_warning("UNEXPECTED_RESPONSE", $sformatf("unexpected response: id %h", id))
continue;
end
end
wait_for_response_ready();
sample_response(current_id, busy);
end
endtask
注意这里的is_valid_response任务,这里执行的内容如下:
protected function bit is_valid_response(tvip_axi_id id);
return
response_stores.exists(id) &&
response_stores[id].size() > 0;
endfunction
而这里的response_stores和sample address中的response_stores是一样的,也就是说这个id的response是否有效的前提是前面已经经历过针对这个id的地址采集。
下面是sample_response的内容
protected virtual task sample_response(
input tvip_axi_id id,
ref bit busy
);
tvip_axi_payload_store store;
store = response_stores[id][0];
store.store_response(get_response(), get_read_data());
if (get_response_last()) begin
store.pack_response();
end_response(store.item);
void'(response_stores[id].pop_front());
busy = 0;
end
endtask
核心的点在于store.store_response(get_response(), get_read_data());store_response表示的就是存取response和read data到store内部的队列中。另外,get_response任务如下:
protected function tvip_axi_response get_response();
return (write_component) ? vif.monitor_cb.bresp : vif.monitor_cb.rresp;
endfunction
protected function tvip_axi_data get_read_data();
return (write_component) ? '0 : vif.monitor_cb.rdata;
endfunction
如果执行get_response_last,也就是最后一次的response的数据pack_response(也就是把store中的response放到item中去存储),然后发送出去。