我是靠谱客的博主 无情雨,最近开发中收集的这篇文章主要介绍SV(UVM)实现多phase pipeline driver建模,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在平台的搭建中,需要关注的重点一是平台的结构,怎么样便于复用,怎么样便于使用,不需要知道内部层次结构就可以很好的配置和使用。另一点就是实现了,驱动怎么实现?monitor怎么实现?sequence怎么实现?这些在VIP里都是加密的,都是“核心机密”。而其他结构agent, coverge collector, scoreboard等等结构基本大同小异。本文主要讨论“实现”这一方面的一小部分内容,给大家一点参考,有不正确的地方请不吝指正。

(转载请注明出处,谢谢!seabeam

按照mentor的分类方法,driver的model分为

Unidirectional Non-Pipelined:   ADPCM, PCM

Bidirectional Non-Pipelined: AMBA APB

Pipelined: AMBA AHB

Out Of Order Pipelined:  AMBA AXI, OCP


前两种相对简单,双向的无非加一个读写判断就搞定了,后两种的实现就比较麻烦,对于新手来说是个不小的挑战。

下面是mentor的例子:

class mbus_pipelined_driver extends uvm_driver #(mbus_seq_item);
...
task run_phase(uvm_phase phase);
@(posedge MBUS.MRESETN);
@(posedge MBUS.MCLK);
fork
do_pipelined_transfer;
do_pipelined_transfer;
join
endtask
...
run_phase里面有两个并行线程,有几个phase,那么就应该有几个并行线程。但是两条并行的线程,同时去取tansaction然后一起驱动岂不是糟糕了?既然是流水线,那么第一个stage只应该驱动transaction 1的第一个phase,而第二个stage则应当同时驱动tansaction 1的第二个phase与transaction 2的第一个phase.如果你打算就这样驱动或者transaction做一些处理,把他们合并起来直接发送,根本不用并行操作,那么请左键右上角的x.

继续前文,关键问题在于两个相同的线程,怎么样让后一个线程在前一个线程的特定时间后延迟一段特定的时间再驱动。没错,do_pipelined_transfer()就是核心中的核心了,看一看怎么实现的:

task automatic do_pipelined_transfer;
mbus_seq_item req;
forever begin
pipeline_lock.get();
seq_item_port.get(req);
accept_tr(req, $time);
void'(begin_tr(req, "pipelined_driver"));
MBUS.MADDR <= req.MADDR;
MBUS.MREAD <= req.MREAD;
MBUS.MOPCODE <= req.MOPCODE;
@(posedge MBUS.MCLK);
while(!MBUS.MRDY == 1) begin
@(posedge MBUS.MCLK);
end
// End of command phase:
// - unlock pipeline semaphore
pipeline_lock.put();
// Complete the data phase
if(req.MREAD == 1) begin
@(posedge MBUS.MCLK);
while(MBUS.MRDY != 1) begin
@(posedge MBUS.MCLK);
end
req.MRESP = MBUS.MRESP;
req.MRDATA = MBUS.MRDATA;
end
else begin
MBUS.MWDATA <= req.MWDATA;
@(posedge MBUS.MCLK);
while(MBUS.MRDY != 1) begin
@(posedge MBUS.MCLK);
end
req.MRESP = MBUS.MRESP;
end
// Return the request as a response
seq_item_port.put(req);
end_tr(req);
end
endtask: do_pipelined_transfer

红色高亮就是关键所在,延时全靠它了。pipeline_lock是一个SV的内建数据类型信号量( semaphore),正是它保证了两个线程的pipeline操作。当第一个线程的第一个phase开始时,信号量锁住,第二个线程需要等待信号量的释放。当第一个线程把第一个phase驱动完毕后,释放信号量,这时候第一个线程开始驱动其二个phase,而第二个线程也可以取数开始驱动第一个phase了。

如果有更多的phase怎么办?mentor没有提及,其实原理是类似的,有n级流水线,那么run_phase()里就应该开启多条并行线程,但是do_pipeline_transfer()里还是一样,只锁住第一个stage即可。sequence就只管不停的发数,driver只管来一个transaction驱动一个,所以是forever无线循环。

这种方法的好处是直观,很符合通常的印象,但是并行线程debug起来可不是那么容易啊。

最后

以上就是无情雨为你收集整理的SV(UVM)实现多phase pipeline driver建模的全部内容,希望文章能够帮你解决SV(UVM)实现多phase pipeline driver建模所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(31)

评论列表共有 0 条评论

立即
投稿
返回
顶部