zoukankan      html  css  js  c++  java
  • System Verilog基础(二)

        这一篇笔记主要记录Procedural,Process,Task and function,Interface和Communication中值得注意的点。

    1.Procedural

        写testbench的时候,除了tb与硬件交互的地方使用非阻塞赋值,tb里面其他地方一律用阻塞赋值,OK

    1 logic [3:0]        d0,d1;
    2 initial    begin
    3     d0 <= 3;
    4     $display("d0 value %0d",d0);    //d0=x;logic在未被初始化的时候是x
    5     d1 = 4;
    6     $display("d1 value %0d d0 value %0d",d1);    //d1=4,d0=x;注意这个时候d0依然是x
    7     #1
    8     $display("d1 value %0d d0 value %0d",d1);    //d1=4,d0=3;只有#1往前走了之后,<=才会赋值生效
    9 end

         Loop循环中的foreach,是专门针对数组轮询时候用的。对二维数组遍历,如下代码:

    1 int data[3][4];
    2 initial
    3     foreach(data[1]) begin
    4         foreach(data[i][j]) begin
    5             </**/>
    6         end
    7         </**/>
    8     end
    9 end

         在两个for循环中,可以在里面直接定义index,例如for(int i; i<10; i++) 这样,如果有两个for里面都定义了int i,这两个index i是相互不影响的。

        哪些地方可以加label? Module...endmodule; begin...end; task...endtask; fork...join; interface...endinterface; 加标签的主要好处是增加代码的可读性,例如下面的代码:

     1 module test();
     2     begin: b0
     3     <...>
     4         begin: b1
     5             <...>
     6         end: b1
     7     end: b0
     8     
     9     begin: b2
    10         <...>
    11     end: b2
    12 endmodule:test

        Final Blocks。这个块在Verilog中没有,当遇到$finish的时候,会进入到final块中。一般用在打印一些信息,注意final块中是不能加延迟#操作的,不然会报错。

    2.Process

        initial块和always块都会产生进程Process。在SV中,可以使用fork来动态地产生子进程。fork有三种形式:fork...join  fork...join_any  fork...join_none 。使用fork...join_none时,不等待子进程执行,直接先执行主进程,就是fork...join_none外面的代码,但是fork...join_none里面的代码在后台也在执行,注意执行的先后顺序。如下代码:

     1 fork: fork 1
     2     begin
     3         #1;
     4     end
     5     begin
     6         #2 7     end
     8 join
     9 $dispaly($time);    // time is 2ns
    10 fork: fork 2
    11     begin
    12         #1;
    13     end
    14     begin
    15         #216     end
    17 join_any
    18 $dispaly($time);    // time is 1ns
    19 fork: fork 3
    20     begin
    21         #1;
    22     end
    23     begin
    24         #225     end
    26 join_none
    27 $dispaly($time);    // time is 0ns

        使用wait fork来等待所有的进程执行完,如下代码,只有exec1(), exec2(), exec3(), exec4()都执行完了,task才会结束。

     1 task mytask;
     2     fork: fork1
     3         exec1();
     4         exec2();
     5     join_any
     6     fork: fork2
     7         exec3();
     8         exec4();
     9     join_none
    10     
    11     wait fork;
    12 endtask

        使用disable fork,可以停止后台挂起的进程。在fork...join_any中disable fork使用的较多,用来检测程序,当fork...join_any中的任何一个监测进程执行OK后,就会使用disable fork来杀死fork中剩余的其他监测进程。

        为了对Process更精细控制,SV中内建有Class,在UVM中使用到。(遇到再更新吧~.~)

    3. task and function

    1 task mytask(a, int b, output logic [15:0]u, v)
    2 // a没有定方向和类型,默认input logic;
    3 // b默认是input方向
    4 // v的方向和类型会继承前一个参数,所以v也是output logic [15:0]
    5     <...>
    6 endtask

        task和function也可以加标签,如下代码:

    1 task mytask(a = 3, int b, output logic [15:0]u, v);
    2 // a的默认值是3,如果传参没有传,就会使用默认值
    3      <...>
    4 endtask: mytask
    5 function my_func (a, int b, output logic [15:0]u, v);
    6     <...>
    7 endfunction: my_func

       C语言有数值传参和指针传参,SV也有,在定义task的时候使用ref关键字去修饰形参,还可以加const,参考C语言的用法。

        task中可以有时间消耗,function中不能有时间消耗。task可以调用function,反过来不可以。

    4. Interface

        使用interface...endinterface来定义,用来解决模块之间的连接,模块和硬件件的连接问题。可以像理解module一样去理解interface,如下代码:

     1 // 定义一个interface类型
     2 interface bus_A (input clk);        //定义interface时可以像module一样有端口
     3     logic         req;
     4     logic [7:0]    addr,data;
     5     logic        start,rdy;
     6 endinterface
     7 // 使用这个interface,在module中例化
     8 module tb_top;
     9     logic clk = 0;
    10     bus_A sb_intf(clk);        //例化
    11     memMode u_inst_mem1(clk,sb_intf); //把memMode模块,通过名字相同的线与sb_intf连接起来
    12 endmodule

        在定义interface的里面,使用modport来对一些信号接口做子集分类,这样在外层module中,例化一个模块,模块可以只连接interface其中的一个子集。

        interface可以像module一样,用#(AWIDTH=8,BWIDTH=9)来定义参数,在传递的过程中来改变值。

        interface里面还可以使用clock块,在实际项目中遇到了再总结吧(~.~)!

        在calss中使用interface,必须使用关键字virtual interface

    5. 同步和通信

        同步和通信有三种:Semaphone, Event, Mailbox。最后一个是用来传递数据的。

    5.1 Semaphones

      解决进程资源间共享问题,提供四个函数:new, put, get, try_get。其中get相当于一个task,里面有延迟,会阻塞其他的get拿到钥匙,try_get相当于一个function,立即执行,不会产生阻塞。下面代码示例:

     1 semaphone sem0 = new(1);    //钥匙数量为1
     2 initial begin:process 0
     3     #10ns
     4     void'(sem0.try_get())    //不会阻塞,拿不到钥匙直接执行下面的语句;拿到钥匙返回值为1
     5     sem0.get();                //不会拿到钥匙,会一直阻塞在这里,直到下面的进程100ns之后把钥匙还了
     6     sem0.put();                //还钥匙
     7 end:process 1
     8 
     9 initial begin:process 1
    10     sem0.get();
    11     #100ns
    12     sem0.put();        //还钥匙,key number 为1
    13 end:process 1

    5.2 Event

        用来触发事件,使用->;用来等待事件使用@或者wait。那么@和wait有什么区别呢?看下面的代码:

     1 event a;    //使用关键字event来声明一个事件a
     2 initial begin
     3     #1;
     4     ->a;
     5 end
     6 initial    begin
     7     #1;
     8     @a;        //第一个进程在1ns后触发了事件a,那么第二个进程在1ns的时候等待a,有可能等的到,有可能等不到,产生竞争
     9 end
    10 initial begin
    11     #1;
    12     wait(a.triggered); //使用wait来等待事件a,这种方式是一定可以等到a的,这是和使用@来等待的区别
    13 end

    wait像是增强版的@,用来解决同一时刻的竞争冒险问题。

    5.3 Mailbox

        可以理解为能存储任意数据类型的队列。先挖坑,以后遇到了再做笔记(~.~)!

  • 相关阅读:
    树状数组——求和问题题解
    java 基础01
    java jdk 配置
    一位资深程序员大牛给予Java初学者的学习路线建议
    汇编 OD 标志位 置位相关指令
    汇编 SETG,SETL ,SETGE, SETLE指令
    汇编 指令lodsb,lodsw,lodsd
    汇编 STOSB, STOSW, STOSD指令
    汇编 LOOP,LOOPD指令
    汇编 STD和CLD指令
  • 原文地址:https://www.cnblogs.com/yiwenbo/p/10299192.html
Copyright © 2011-2022 走看看