四、控制流语句

控制流

if-else

if-else语句根据不同的条件来决定是否执行哪一部分代码。

	// begin and end act like curly braces in C/C++.
	if (enable == 1'b1) begin
	  data = 10; // Decimal assigned
	  address = 16'hDEAD; // Hexadecimal
	  wr_enable = 1'b1; // Binary
	end 
	else begin
	  data = 32'b0;
	  wr_enable = 1'b0;
	  address = address + 1;
	end

此外介绍几种SV独特的if语句

  • unique-if/unique0-if

对于unique-if ,如果condition没有一个匹配且没有加else语句,则会报告一个错误;如果超过1个condition匹配,也会报告错误;
unique0-if与unique-if的不同之处在于,如果没有一个condition匹配也不会报错;

module tb;
  int x = 4;
 
    initial begin
        // This if else if construct is declared to be "unique"
    // Error is not reported here because there is a "else"
        // clause in the end which will be triggered when none of
        // the conditions match
      unique if (x == 3) 
          $display ("x is %0d", x);
      else if (x == 5)
          $display ("x is %0d", x);
        else
          $display ("x is neither 3 nor 5");      
 
        // When none of the conditions become true and there
        // is no "else" clause, then an error is reported
      unique if (x == 3) 
          $display ("x is %0d", x);
      else if (x == 5)
          $display ("x is %0d", x);
    end
endmodule
  • priority-if

如果condition没有一个匹配且没有加else语句,则会报告一个错误;如果有多个condition匹配,排在前面的优先级最高,且执行完最高的优先级后退出选择;

module tb;
	int x = 4;
  
  	initial begin    
      	// Exits if-else block once the first match is found
      	priority if (x == 4)
      		$display ("x is %0d", x);
      else if (x != 5)
      		$display ("x is %0d", x);
  	end
endmodule	

case

当需要检查多个值的变量的情况下使用Case语句,而不是使用多个嵌套的if-else语句

	case(address)
	0 : $display ("It is 11:40PM");
	1 : $display ("I am feeling sleepy");
	2 : $display ("Let me skip this tutorial");
	default : $display ("Need to complete");
	endcase

case语句以关键字case开头,以关键字endcase结尾。
在这两个关键字中列出了这些case条件和相应的希望执行的语句。
和if-else一样,建议在case语句中添加default case语句,因为如果组合逻辑Verilog HDL建模时,if-else和case-endcase语句中没有涵盖所有的情况(在If中没有’else’或者在Case中没有’default’),那么综合工具可能会推断出Latch。

下面介绍几种SV独特的case语句:

  • unique,unique0 case

对于unique case ,如果case没有一个匹配且,则会报告一个错误;如果超过1个condition匹配,也会报告错误,同时执行第一个匹配到的case;
unique0-case与unique-case的不同之处在于,如果没有一个case匹配也不会报错;

module tb;
  bit [1:0]   abc;
 
  initial begin
    abc = 1;
 
    // None of the case items match the value in "abc"
    // A violation is reported here
    unique case (abc)
      0 : $display ("Found to be 0");
      2 : $display ("Found to be 2");
      //使用unique case此时多加default
    endcase
  end
endmodule
  • priority case

至少有一个条件选项的值与条件表达式匹配
如果有多个条件选项的值与条件表达式匹配,必须执行第一个匹配分支

	bit [2:0] a;
	priority case(a) // 值4,5,6,7会引起一个运行时警告
	   3'b00?: $display("0 or 1");
	   3'b0??: $display("2 or 3");
	endcase

for/foreach

	initial beigin
		bit[31:0] src[5],dst[5];
		for(int i=0;i<$size(src);i++)
			src[i]=[i];
		foreach(dst[j])
			dst[j]=src[j]*2;
	end

在foreach循环中只需要指定数组名并在其后方括号中给出索引变量,SV会自动遍历数组中的元素。索引变量将会自动声明,并只在循环内收敛。

利用foreach初始化并遍历多维数组:

	int md[2][3]='{'{0,1,2},'{3,4,5}};
	initial begin
		$display("Initial value: ");
		foreach(md[i,j])
			$display("md[%0d][%0d]=%0d",i,j,md[i][j]);
		$display("New value: ");
		md='{'{9,8,7},'{3{32'd5}}};//对数组最后三个元素赋值为5
		foreach(md[i,j])
			$display("md[%0d][%0d]=%0d",i,j,md[i][j]);
	end

repeat循环对循环体执行固定的次数,如果表达式被评估为未知或者高阻,那么应该认为是零次,不应该执行循环体。

repeat

repeat循环对循环体执行固定的次数,如果表达式被评估为未知或者高阻,那么应该认为是零次,不应该执行循环体。

	module tb;
	  bit clk;
	  always #10 clk = ~clk;
	 
	  initial begin
	    bit [2:0] num = $random;
	 
	    $display ("[%0t] Repeat loop is going to start with num = %0d", $time, num);
	    repeat (num) @(posedge clk);
	    $display ("[%0t] Repeat loop has finished", $time);
	    $finish;
	  end
	endmodule

while

如果判断的条件返回true,则while语句将重复执行语句块中的代码。While循环通常不用于实际的硬件建模,但是它们用于测试平台(验证)。与其他语句块一样,它们由begin和end分隔。

	while (free_time) begin
		$display ("Continue with webpage development");
	end

do-while

do…while循环语句和while循环语句有一点区别,也就是do…while循环语句在循环体的结束处评估循环条件,也就是do…while循环至少执行一次循环体。

	 do
     	<begin>
         	//循环体
     	 <end>
     while(<expression>);

forever

在SV中,always块不能存在于类和其他过程块中,所以用forever代替。格式如下:

	always begin
    // Multiple statements
  	end
	class Monitor;
	  virtual task run();
	    forever begin
	      @(posedge vif.clk);
	      if (vif.write & vif.sel)
	        // Capture write data
	      if (!vif.write & vif.sel)
	        // Capture read data
	    end
	  endtask
	endclass
	 
	module tb;
	  Monitor mon;
	 
	  // Start the monitor task and allow it to continue as 
	  // long as there is activity on the bus
	  initial begin
	    fork
	      mon.run();
	    join_none
	  end
	endmodule

为了防止循环体在delta时间内产生无限循环,导致仿真挂起,forever循环体内部必须带有时序控制或者disable语句。

break

类C语言的break声明立即结束循环操作。循环不会重新执行,除非执行流程重新到达循环的起点

1 // find first bit set within a range of bits
 2 always_comb begin
 3     first_bit = 0;
 4     for (int i=0; i<=63; i=i+1) begin
 5         if (i < start_range) continue;
 6         if (i > end_range) break; // exit loop
 7         if ( data[i] ) begin
 8             first_bit = i;
 9             break; // exit loop
10         end
11     end // end of the loop
12     ... // process data based on first bit set
13 end  

continue

类C语言的continue声明跳转到循环的末尾并执行循环的控制。使用continue声明时,不需要对代码添加命名的begin…end块,而这在使用disable声明时是必要的。

1 logic [15:0] array [0:255];
2 always_comb begin
3     for (int i = 0; i <= 255; i++) begin : loop
4         if (array[i] == 0)
5           continue; // skip empty elements
6         transform_function(array[i]);
7     end // end of loop
8 end

return

system verilog增加了类C语言的return声明,用于从一个非void函数中返回数值或者从一个void函数或任务返回。return声明可以在任务或函数执行流程的任意一点执行。当return声明执行后,任务或者函数立即退出而不需要执行到任务或者函数的末尾。

1 task add_up_to_max (input [ 5:0] max,
2                     output [63:0] result);
3     result = 1;
4     if (max == 0) return; // exit task
5     for (int i=1; i<=63; i=i+1) begin
6         result = result + result;
7         if (i == max) return; // exit task
8     end
9 endtask

disable

  • disable :用于在多进程的场景下终止一个或多个进程

disable语句可以用在task或者块中去终止指定的task或块,包括终止disable语句所在的块或者task。disable也可以用在function中去终止task或者块,但不能用于终止function。当在function中用dsiable语句终止了一个task或者块,而这个task或者块刚好又是这个function的caller, 这种情况的结果是未知的。

task proc_a;
    begin
    ...
    ...
    if (a == 0)
        disable proc_a; // return if true
    ...
    ...
    end
endtask

event

event是一个静态对象句柄,用于在两个或多个同时活动的进程之间进行同步。 一个进程将触发事件,另一个进程将等待事件。

【1】可以赋值或与其他事件变量进行比较
【2】可以赋值为空
【3】当赋值给另一个事件时,两个变量都指向同一个同步对象
【4】可以传递给队列,函数和任务

如何触发并等待事件?

【1】可以使用->或->>运算符触发命名事件
【2】进程可以使用@运算符或.triggered等待事件

module tb;
 
  //创建一个事件变量,进程可用于触发和等待
  event event_a;
 
  // 线程1:使用“->”运算符触发事件
  initial begin
    #20 ->event_a;
    $display ("[%0t] Thread1: triggered event_a", $time);
  end
 
  // 线程2:使用“ @”运算符等待事件
  initial begin
    $display ("[%0t] Thread2: waiting for trigger ", $time);
    @(event_a);
    $display ("[%0t] Thread2: received event_a trigger ", $time);
  end
 
  // 线程3:使用“ .triggered”等待事件
  initial begin
    $display ("[%0t] Thread3: waiting for trigger ", $time);
    wait(event_a.triggered);
    $display ("[%0t] Thread3: received event_a trigger", $time);
  end
endmodule  
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值