Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
System verilog 避免支持SVA序列处理流水线事务的代码_System Verilog_System Verilog Assertions - Fatal编程技术网

System verilog 避免支持SVA序列处理流水线事务的代码

System verilog 避免支持SVA序列处理流水线事务的代码,system-verilog,system-verilog-assertions,System Verilog,System Verilog Assertions,假设我们有一个协议,上面写着。一旦主设备将req设置为fill,从设备将通过rsp发出4次传输信号: 整个事务的SVA序列是(假设从机可以在trans周期之间插入idle周期): 现在,假设允许主机对请求进行管道处理。这意味着在完成4个trans循环之前,允许开始下一个fill: 上面的SVA序列没有帮助,因为对于第二个fill循环,它将错误地匹配4个trans循环,使最后一个trans循环处于“浮动”状态。只有在先前的填充循环匹配后,才需要开始匹配trans循环 序列需要在单个评估中不可用

假设我们有一个协议,上面写着。一旦主设备将
req
设置为
fill
,从设备将通过
rsp
发出4次传输信号:

整个事务的SVA序列是(假设从机可以在
trans
周期之间插入
idle
周期):

现在,假设允许主机对请求进行管道处理。这意味着在完成4个
trans
循环之前,允许开始下一个
fill

上面的SVA序列没有帮助,因为对于第二个
fill
循环,它将错误地匹配4个
trans
循环,使最后一个
trans
循环处于“浮动”状态。只有在先前的
填充
循环匹配后,才需要开始匹配
trans
循环

序列需要在单个评估中不可用的全局信息。基本上,它需要知道它的另一个实例正在运行。我能想到的实现这一点的唯一方法是使用一些RTL支持代码:

int num_trans_seen;
bit trans_ongoing;
bit trans_done;
bit trans_queued;

always @(posedge clk or negedge rst_n)
  if (!rst_n) begin
    num_trans_seen;
    trans_ongoing <= 0;
    trans_done <= 0;
    trans_queued <= 0;
  end
  else begin
    if (trans_ongoing)
      if (num_trans_seen == 3 && req == trans) begin
        trans_done <= 1;
        if (req == fill || trans_queued)
          trans_queued <= 0;
        else
          trans_ongoing <= 0;
        num_trans_seen == 0;
      end
    else
      if (trans_queued) begin
        trans_queued <= 0;
        trans_ongoing <= 1;
      end

    if (trans_done)
      trans_done <= 0;
  end
这应该行得通,但我并不特别高兴我需要支持代码。这里面有很多冗余,因为我基本上重新描述了事务是什么以及流水线是如何工作的。它也不容易重复使用。
序列
可以放在一个包中,然后导入到其他地方。支持代码只能放在某个模块中并重用,但它是与存储序列的包不同的逻辑实体


这里的问题是:在不需要支持代码的情况下,是否有任何方法可以编写序列的流水线版本?

一种可能的解决方案可以通过以下两种断言实现

对于第一个图像-

(req == fill) && (rsp == idle) |=> ((rsp == trans)[->1])[*4]
第二张图片-

(req == fill) && (rsp == trans) |=> ((rsp == trans)[->1])[*0:4] ##1 (rsp == idle) ##1 ((rsp == trans)[->1])[*4]
一个问题是,如果每个周期上都有连续的“填充”请求(连续的4个“填充”请求,没有任何中间的“空闲”),那么第二个断言将不会为每个“填充”请求计算“转换”周期(相反,它将只在第二组“转换”周期本身上完成)


到目前为止,我无法修改给定错误的断言。

在传输开始之前,rsp似乎总是处于空闲状态。如果rsp的
idle
是一个常量值,并且它是
trans
永远不会出现的值,那么您可以使用:

req == fill ##0 (rsp==idle)[->1] ##1 trans[*4];
当管道支持1至3级时,上述操作应有效

对于4+深度的管道,我认为您需要一些辅助代码。断言的成功/失败块可用于取消已完成的
trans
计数;这样可以避免编写额外的RTL。属性中的局部变量可用于采样填充的计数值。采样值将用作标准,以开始对预期的传输模式进行采样

int fill_req;
int trans_rsp;
always @(posedge clk, negedge rst_n) begin
  if(!rst_n) begin
    fill_req <= '0;
    trans_rsp <= '0;
  end
  else begin
    if(req == fill) begin
      fill_req <= fill_req + 1; // Non-blocking to prevent risk of race condition
    end
  end
end

property fill_trans();
  int id;
  @(posedge clk) disable iff(!rst_n)
  (req == fill, id = fill_req) |-> (rsp==idle && id==trans_rsp)[->1] ##1 trans[*4];
endproperty

assert property (fill_trans()) begin
  // SUCCESS
  trans_rsp <= trans_rsp + 1; // Non-blocking to prevent risk of race condition
end
else begin
  // FAIL
  // trans_rsp <= trans_rsp + 1; // Optional for supporting pass after fail
  $error("...");
end
除非没有提到另一个限定符,否则不能使用典型的
assert属性()expect
语句,该语句允许等待属性评估(§16.17 expect语句)


我尝试重新创建您的描述行为以进行测试

解码rsp的空闲和传输之间的差异是否容易?我的理解是,如果另一个“填充”在“填充”和4个“传输”周期之间到达,则后面的“填充”将被简单忽略(在图中,第二个“填充”将被忽略)。请评论我的理解。@KaranShah不,第二次填充是在正在进行的循环完成后开始的4个“trans”循环。@Greg是的,它们是枚举类型。在一个时钟中你看到空闲,在另一个时钟中你看到传输。要弄清楚发生了什么事是很容易的。将TRANS循环映射到适当的填充是困难的部分。不正确。注意,我说过从机可以在
trans
之间插入
idle
周期。如果
trans
周期以连续数据包的形式出现,If将很容易。@Tudor修改了断言,实际上还有另一种情况,第二个断言将无法正常运行。当
req
出现时,在
trans
周期中,很明显它是管道化的。即便如此,你也不知道它是在4个周期中的哪一个周期出现的。当
req
idle
周期中出现时,您无法知道它是
idle
,因为管道是空的,或者它是两个
trans
周期之间的
idle
。是的,但是当req在idle周期中出现时,我们当然可以知道空闲后必须有4个trans周期。所以第一个断言应该是真的,不管它是流水线请求还是普通请求。@KaramShah不,这是假的。你不能仅仅通过查看
rsp
来判断请求的位置(完成请求后或请求期间)。这假设在事务的4个
trans
周期之间不存在
idle
周期,但事实并非如此。我想我没有真正理解你之前的问题,你问
idle
是否容易与
trans
区分。你的波形在4个trans之间没有idle,所以我简化了
(trans[->1])[*4]
。如果同一个填充请求的两个trans之间允许空闲,那么第二个示例在修改后仍然有效。
id==trans\u rsp
将阻止一组trans的采样,直到前一个完成。我问过如何区分
trans
idle
,因为我需要了解您的协议。我见过一些协议,其中rsp的含义基于位限定符,而其他协议只能从其相对位置确定。不过,第二个示例使用支持代码,这正是我想要避免的。纯SVA可能不可能。你能添加另一个显示更坏情况的波形吗?是否有任何附加的限定符
req == fill ##0 (rsp==idle)[->1] ##1 trans[*4];
int fill_req;
int trans_rsp;
always @(posedge clk, negedge rst_n) begin
  if(!rst_n) begin
    fill_req <= '0;
    trans_rsp <= '0;
  end
  else begin
    if(req == fill) begin
      fill_req <= fill_req + 1; // Non-blocking to prevent risk of race condition
    end
  end
end

property fill_trans();
  int id;
  @(posedge clk) disable iff(!rst_n)
  (req == fill, id = fill_req) |-> (rsp==idle && id==trans_rsp)[->1] ##1 trans[*4];
endproperty

assert property (fill_trans()) begin
  // SUCCESS
  trans_rsp <= trans_rsp + 1; // Non-blocking to prevent risk of race condition
end
else begin
  // FAIL
  // trans_rsp <= trans_rsp + 1; // Optional for supporting pass after fail
  $error("...");
end
sequence fill_trans;
  int cnt;                                // local variable
  @(posedge clk)
  (req==FILL,cnt=4) ##1 (                 // initial request set to 4
    (rsp!=TRANS,cnt+=4*(req==FILL))[*]    // add 4 if new request
    ##1 (rsp==TRANS,cnt+=4*(req==FILL)-1) // add 4 if new request, always minus 1
  )[*] ##1 (cnt==0);                      // sequence ends when cnt is zero
endsequence
always @(posedge clk) begin
  if(req==FILL) begin
    expect(fill_trans);
  end
end