systemverilog学习 ---随机化(2)

Constraint inside

前面的约束,采用条件表达式>,倘若随机值是有限个值,并且没有明显的规律,总结表达式会较为困难。sv可以使用inside操作符,表示随机变量会从inside块中取值.
inside块里面可以是变量,常数和范围。inside之后用大括号,把取值放于括号内。其声明形式如下:

constraint addr_range {addr inside {...};}

对于范围表示要使用[],其声明形式如下:

constraint addr_range {addr inside {[5:10]};}

若是一系列的值,通过逗号分隔。

constraint addr_range {addr inside {1,3,5,7,9};}

对于上述的可以混合使用。

constraint addr_range {addr inside {1,3,[5:10],12.[13:15]};}

吐过想要排除一些值,可以使用!(感叹号),对整个约束取反。

constraint addr_range {addr !(inside{[5:10]});11}

一些随机变量也可以被使用在inside语句块中,如下所示:

rand bit [3:0]	start_addr	;
rand bit [3:0]	end_addr	;
rand bit [3:0]	addr		;
constraint addr_range {addr inside {[start_addr : end_addr]};}

下面给出一个例子:

class packet;
    rand bit    [3:0]   addr        ;
    rand bit    [3:0]   start_addr  ;
    rand bit    [3:0]   end_addr    ;

    constraint addr_1_range {addr inside {[start_addr : end_addr]};}
endclass

module constr_inside;
    initial begin
        packet pkt;
        pkt = new();
        $display("----------------------------------------------");
        repeat(3) begin
            pkt.randomize();
            $display("start_addr = %0d, end_addr = %0d", pkt.start_addr, pkt.end_addr);
            $display("\t addr = %0d", pkt.addr);
            $display("----------------------------------------------");
        end
    end


endmodule

由下面输出结果看出,addr都是在开始地址和结束地址之间。输出结果如下:

在这里插入图片描述

dist constraint

我们还可能需要控制随机值的概率分布,sv提供dist操作符,可以实现带权重分布,dist需要紧跟一系列的值和权重。其声明形式如下:

value := weight    or
value :/ weight

其中value表示把希望的值赋给一个随机变量,权重表示在随机化过程中这个数值所被考虑的频次。需要注意的是:

  • 数值和权重可以是常数或者是变量
  • 数值可以是一个值,或者一个范围
  • 一个数值的默认权重是1
  • 权重和即所有的weight的和加起来不一定是100,可以自由发挥,并不影响总的概率是1.

在这里插入图片描述
value:/weight表示对于值value赋予权重weight,但是如果value是一个范围是,范围内的值会平分权重weight,下面的李忠,10-12共三个取值,因此每个取值概率是8/3.
在这里插入图片描述

class packet;
    rand bit [3:0]  addr    ;

    constraint addr_range {addr dist {2 := 5, 7 := 8, 10 := 12};}

endclass

module constr_dist;

    initial begin
        packet pkt;
        pkt = new();
        $display("----------------------------------------");
        repeat(10) begin
            pkt.randomize();
            $display("\t addr = %0d", pkt.addr);
            $display("----------------------------------------");
        end
    end

endmodule

其输出结果是:
在这里插入图片描述
理应是10的输出个数最多的,输出最少的个数是2。

class packet;

    rand bit [3:0]  addr_1  ;
    rand bit [3:0]  addr_2  ;

    constraint addr_1_range{addr_1 dist {2 := 5, [10:12] := 8};}
    constraint addr_2_range{addr_2 dist {2 :/ 5, [10:12] :/ 8};}

endclass

module constr_dist;

    initial begin
        packet pkt;
        pkt = new();

        $display("-------------------------------------------");
        repeat(10) begin
            pkt.randomize();
            $display("\t addr_1 = %0d", pkt.addr_1);
        end
        $display("-------------------------------------------");
        $display("-------------------------------------------");
        repeat(10)begin
            pkt.randomize();
            $display("\t addr_2 = %0d", pkt.addr_2);
        end
        $display("-------------------------------------------");
    end

endmodule

这里需要理解的是,对于addr_1中,2的权重5,10,11,12对应的权重都是8.而在addr_2中,2的权重是5,而10,11,12的权重都是3/8。因此其输出结果是:
在这里插入图片描述

implication constraints

implication是隐含的意思,systemverilog提供隐含操作符(->)。可以用来声明两个变量之间的关系。一般被放置于表达式和约束条件之间。即:

expression -> contraint

只有当左面的表达式为真的时候,右边的约束才会被考虑。

class packet;

    rand bit [3:0]      addr        ;
    string              addr_range  ;

    constraint address_range {(addr_range == "small") -> (addr < 8);}
endclass

module constr_implication;

    initial begin
        packet pkt;
        pkt = new();

        pkt.addr_range = "small";
        $display("---------------------------------------------");
        repeat(4) begin
            pkt.randomize();
            $display("\t addr_range = %s addr = %0d", pkt.addr_range, pkt.addr);
        end
        $display("---------------------------------------------");
    end

endmodule

如上面例子,若addr_range等于small的话,那么才会有约束的随机化,如若不是small的话,则约束将不会生效。输出结果是:
在这里插入图片描述

if else 的约束

if else的语句块中也允许约束的条件执行,如果这个表达式是真,那么在一个约束块中所有的约束都会被满足,否则是在else的语句块中的约束会被满足。

class packet;

    rand bit [3:0]  addr        ;
    string          addr_range  ;

    constraint address_range {
        if(addr_range == "small")
            addr < 8;
        else
            addr > 8;
    }

endclass

module constr_if_else;

    initial begin
        packet pkt;
        pkt = new();
        pkt.addr_range = "small";
        $display("----------------------------------------------------");
        repeat(3) begin
            pkt.randomize();
            $display("\t addr_range = %s addr = %0d", pkt.addr_range, pkt.addr);
        end
        $display("----------------------------------------------------");
        pkt.addr_range = "high";
        $display("----------------------------------------------------");
        repeat(3)begin
            pkt.randomize();
            $display("\t addr_range = %s addr = %0d", pkt.addr_range, pkt.addr);
        end
        $display("----------------------------------------------------");
    end

endmodule

上面例子中,若addr_range是small,则随机化后的addr值都会小于8,如果是high的话,那么随机化后的addr值都会大于8.因此其输出结果如下所示:
在这里插入图片描述

foreach constraint

在systemverilog中的contraint块中也支持foreach循环。使用foreach对于数据的约束将是非常简单的。因此也叫做循环约束。在约束数组时,我们要指定或者约束动态数组的大小。其约束形式如下所示:

constraint constraint_name { foreach ( variable[iterator] )  variable[iterator] <..conditions..>  }

下面的例子:

class packet;

    rand byte addr [];
    rand byte data [];
    
    constraint avalues {
        foreach(addr[i])
            addr[i] inside {4, 8, 12, 16};
    }

    constraint dvalues {
        foreach(data[j])
            data[j] > 4 * j;
    }

    constraint asize {addr.size < 4;}
    constraint dsize {data.size == addr.size;}
endclass

module constr_iteration;

    initial begin
        packet pkt;
        pkt = new();

        $display("--------------------------------------------");
        repeat(3) begin
            pkt.randomize();
            $display("\t addr-size = %0d data-size = %0d", pkt.addr.size(), pkt.data.size());
            foreach(pkt.addr[i])
                $display("\t addr = %0d data = %0d", pkt.addr[i], pkt.data[i]);
                $display("--------------------------------------------");
        end
    end

endmodule

显示addr 动态数组的元素必须时4,8,12,16,且大小必须小于4,而data数组的元素必须大于它的Index的4倍。约束两个动态数组的大小相等。其输出结果如下所示,当数组的大小为0时,则没有元素输出。
在这里插入图片描述

disable constraint

使用constraint_mode方法不使能一个类中的约束。默认情况下所有约束都会被使能。类似我们前文所提出的rand_mode方法。constraint_mode方法可以用来不使能任何特定的约束块。

  • constraint_mode(1)表示约束被使能
  • constraint_mode(0)表示约束被不使能
  • 返回约束块的状态
    其声明形式如下:
<object_hanlde>.<constraint_block_name>.constraint_mode(enable);
//enable == 1, constraint block enable
//enable == 0, constraint block disable

下面这个例子没有不使能约束条件,因此会随机选取5或者10中一个数进行打印输出,代码如下所示:
在这里插入图片描述
其输出结果是:
在这里插入图片描述
但是若在上面例子中加上不使能约束,则:
在这里插入图片描述
其输出结果是:
在这里插入图片描述
其实contraint_mode()可以返回约束块的状态:

class packet;

    rand bit [3:0]  addr;
    constraint addr_range {addr inside {5, 10 , 14};}

endclass

module static_constr;

    initial begin
        packet pkt;
        pkt = new();

        $display("Before Constraint disable");
        $display("Value of constraint mode = %0d", pkt.addr_range.constraint_mode());
        pkt.randomize();
        $display("\t addr = %0d", pkt.addr);

        //disabling constraint
        pkt.addr_range.constraint_mode(0);

        $display("After Constraint disable");
        $display("Value of constraint mode = %0d", pkt.addr_range.constraint_mode());
        pkt.randomize();
        $display("\t addr = %0d", pkt.addr);
    end

endmodule

其输出结果是:
在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值