SV学习(3)——接口interface、modport、时钟块clocking
SV学习(3)——接口interface、modport、时钟块clocking
- 1. 接口interface
- 2. modport
- 3. 时钟块clocking
- 3.1. 驱动和采用的竞争问题
- 3.2. clocking待补充....
========
链接: interface中的clocking
========
1. 接口interface
SV引入了一个重要的数据类型:interface。主要作用有两个,一是简化模块之间的连接;二是实现类和模块之间的通信。
使用接口使得连接更加简洁而不易出差,如果需要在一个接口中放入一个新的信号,就只需要在接口定义和实际使用这个接口的模块中做对应的修改,而不需要改变其他模块。接口不可以例化,但是可以使用接口的指针,找到接口的实例,然后再找接口实例中的信号。
接口使用方法:
- 在interface的端口列表只需要定义时钟、复位等公共信号,或者不定义任何端口信号,转而在变量列表中定义各个需要跟DUT和TB连接的logic变量。
- interface可以用参数化方式提高复用性(parameter)
- 对于有对应interface的DUT和TB,在其例化的时候,也只需要传递匹配的interface变量名即可完成interface的变量传递
由于接口即可以在硬件上(module)使用,又可以在软件上(class)使用,interface作为SV中唯一的硬件和软件环境的媒介交互,modport可以进一步限定信号传输的方向,避免端口连接的错误。
接口中使用task和function:
- 接口可以包含task和function,也可以在接口外部或者内部
- 如果task和function定义在模块中,使用层次结构名称,它们必须在接口中声明为extern或在modport中声明为export
- 多个模块的任务名不可以重复
下面举两个接口的例子:
使用interface接口的一位全加器
`timescale 1ns / 1nsinterface if_port (input bit clk); // 声明接口logic a, b, cin, sum, cout; // 声明所有的连接线clocking cp @ (posedge clk); // 声明在同一个时钟变化下,连接线的方向output a, b, cin;endclockingclocking cn @ (negedge clk); // 下降沿出发input a, b ,cin, sum, cout;endclockingmodport simulus (clocking cp); // 声明端口的输入输出modport adder (input a, b, cin, output cout, sum);modport monitor (clocking cn);endinterfacemodule simulus (if_port.simulus port); // 使用接口的激励模块always @ (port.cp) beginport.cp.a <= $random() % 2;port.cp.b <= $random() % 2;port.cp.cin <= $random() % 2;end endmodule: simulusmodule adder (if_port.adder port); // 一位加法器 // assign {port.cout, port.sum} = {port.a + port.b + port.cin}; // 好久没写代码,犯了这样的错assign {port.cout, port.sum} = port.a + port.b + port.cin; endmodule: addermodule monitor (if_port.monitor mon); // 检测模块,在时钟的下降沿打印结果always @ (mon.cn) begin$display ("%d + %d + %d = %d %d", mon.cn.a, mon.cn.b, mon.cn.cin, mon.cn.cout, mon.cn.sum, $time);end endmodulemodule top ( );timeunit 1ns;timeprecision 1ns;bit clk = 0;;if_port port (clk); // 实例化所有模块,并连接接口simulus sim (port.simulus);adder add (port.adder);monitor mon (port.monitor);always #10 clk = ~clk;endmodule
使用interface接口的读存储器
// interface_exampleinterface membus ( // 声明接口input logic clk ); // port和module的port一样,用于top的// 声明用于内部模块例化的连接logic mrdy ;logic wen ;logic ren ;logic [ 7: 0] addr ;logic [ 7: 0] c2m_data;logic [ 7: 0] m2c_data;wor status ; // 对于确定了方向的可以在interface的port里面声明,如clk, // 而对于随着模块不同、方向不同的用logic先声明,然后再用modport指明具体方向task reply_read (input logic [ 7: 0] data,integer delay);#delay;@ (negedge clk)mrdy = 1'b0;m2c_data = data; // slave回复数据@ (negedge clk)mrdy = 1'b1; endtasktask read_memory (input logic [ 7: 0] raddr ,output logic [ 7: 0] data);@ (posedge clk);ren = 1'b0;addr = raddr; // master申请读数据@ (negedge mrdy);@ (posedge clk);data = m2c_data; // master得到数据ren = 1'b1;endtask// 在接口中使用modport,将信号分组并指定方向modport master (output wen, ren, addr, c2m_data, status,input mrdy, m2c_data,import read_memory); modport slave (input wen, ren, addr, c2m_data, status,output mrdy, m2c_data,import reply_read);endinterface/* *************** mem_core *************** */ module mem_core (membus.slave mb); // 用salve接口声明logic [ 7: 0] mem [ 255: 0];initial beginfor (int i = 0; i < 256; i++)mem[i] = i;endassign mb.status = 1'b0;always @ (negedge mb.ren)mb.reply_read (mem[mb.addr], 100); endmodule/* *************** cpu_core *************** */ module cpu_core (membus.master mb); // 用master接口声明assign mb.status = 1'b0;initial beginlogic [ 7: 0] read_data;mb.read_memory (8'b0001_0000, read_data);$display ("Read Result", $time, read_data);end endmodule/* *************** top *************** */ module top ();wor status; // wor:当有多个驱动源驱动wor型数据时,将产生线或结构logic clk = 1'b0;membus mb (clk);// mem_core mem (mb.slave);mem_core mem (mb);cpu_core cpu (mb.master);initial beginfor (int i = 0; i <= 255; i++)#1 clk = ~clk;endendmodule
关于interface的使用,大概知道了怎么用,接口中端口的调用没问题,比如在顶层top中实例化mem模块和cpu模块,这俩的端口连接可以用接口实现,在interface接口中,把端口的变量名声明好,再用modport将信号分组并指定输入输出方向;
但是具体的细节不太了解,比如在接口中定义了任务,如何在各自的模块中调用任务,看别人博客说是要添加export声明,但是我却用了import解决了,不懂,但是成了
2. modport
使用modport将接口中的信号分组
实现一个简单的仲裁器接口,并在仲裁器中使用接口,
// 简单接口
interface arb_if (input bit clk);logic [1:0] grant, request;logic rst;
endinterface// 仲裁器
module arb (arb_if arbif);...always @(posedge arbif.clk or posedge arbif.rst) beginif (arbif.rst == 1'b1)arbif.grant <= 2'b00;elsearbif.grant <= next_grant;end...
endmodule// 测试平台
module test (arb_if arbif);...initial begin...@(posedge arbif.clk);arbif.request <= 2'b01;$display ("@%0t: Drove req = 01", $time);repeat (2) @(posedge arbif.clk);if (arbif.grant != 2'b01)$display ("@%0t: a1: grant != 2'b01", $time);$finish;end...
endmodule// 顶层
module top; bit clk;always #5 clk = ~clk;arb_if arbif(clk);arb a1(arbif);test t1(arbif);
endmodule
上面arb在接口中使用了点对点的无信号方向的连接方式;
下面在接口中使用modport结构能将信号分组并指定方向;
// 使用mofport的接口
interface arb_if (input bit clk);logic [1:0] grant, request;logic rst;modport TEST (output request, rst,input grant, clk);modport DUT (input request, rst, clk,output grant);modport MONITOR (input request, grant, rst, clk);
endinterface// 仲裁器
module arb (arb_if.DUT arbif);...
endmodule// 测试平台
module test (arb_if.TEST arbif);...
endmodule // 顶层
module top;bit clk;always #5 clk = ~clk;arb_if arbif(clk);arb a1(arbif);test t1(arbif);
endmodule
两种顶层模块是一样的,因为modpoer在模块首部指明,在模块例化时就不需要指明;
在接口中不能例化模块,但是可以例化其他接口
3. 时钟块clocking
3.1. 驱动和采用的竞争问题
在RTL设计中,在同一个时间片内,可能会有一个信号同时被读取和写入,那么读取到的数据有可能会是旧数值也有可能是新数值,用非阻塞赋值 <= 就可以解决这个问题。但是在测试程序中,不能确保采集到DUT产生的最新值;
接口块可以使用时钟块来指定同步信号相对于时钟的时序。
在时钟上升沿采样信号,只看vld信号(1->0)就会疑惑采样到的是1还是0,在RTL仿真时,是看不到真实的物理时序信息的,但实际采样到的是1;真实电路对应的时vld_actual信号,它的变化会较clk有一个detal-cycle的延迟,这样看在时钟上升沿采集到的是1。
我们可以人为的设置加大delay,这样看波形的时候就会显示vld_actual的,让待采样数据的沿变不和时钟的沿变在一起。
还有一种方法就是,设置采样vld信号的时间,设置在时钟上升沿之前 #t 采样,这样采出来的数据也是准确的;
同样也可以设置信号输出时间,设置在时钟上升沿之后 #t 输出,这样输出的数据也是准确的;
就类似与模拟建立保存时间,在时序上在波形上,看到肉眼可见的延迟。
3.2. clocking待补充…
SV学习(3)——接口interface、modport、时钟块clocking相关推荐
- System Verilog学习笔记—接口interface
目录 0.interface的直观理解 1.使用端口的TB与DUT通信 2.使用接口的TB与DUT通信 3.使用modport将interface中的信号分组 4.接口中的clocking block ...
- systemverilog-接口和时钟块
目录 一.接口 1.1接口的意义 1.2接口的定义 1.3 modport 1.4 接口的优缺点 1.5 虚接口 二.时钟块 2.1 时钟块的意义 2.2 时钟块的声明 三.仿真调度机制 一.接口 1 ...
- SV知识点总结-接口
接口 通过端口实现模块之间的连接 实际上的操作是,首先定义两个需要连接的模块A(变量为a,b)和模块B(变量为c,d).再定义一个interface C,其变量分别为e,f.在顶层中将模块C发别与模块 ...
- SV学习(8)——随机约束和分布、约束块控制
SV学习(8)--随机约束和分布.约束块控制 1. 随即约束和分布 1.1. 为什么需要随机? 1.2. 要随机做什么? 1.3. 声明随机变量的类 1.4. 什么是约束 1.5. 权重分布 1.6. ...
- go struct 静态函数_Go语言学习笔记(四)结构体struct 接口Interface 反射reflect...
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套: go中的struc ...
- Go 学习笔记(35)— Go 接口 interface (接口声明、接口初始化、接口方法调用、接口运算、类型断言、类型查询、空接口)
1. 接口概念 接口是双方约定的一种合作协议.接口实现者不需要关心接口会被怎样使用,调用者也不需要关心接口的实现细节.接口是一种类型,也是一种抽象结构,不会暴露所含数据的格式.类型及结构. 接口内部存 ...
- SV学习(2)——过程语句、函数和任务、变量声明周期
SV学习(2)--过程语句.函数和任务 1. 过程语句 1.1. 硬件过程块 1.2. 赋值语句 1.3. 控制语句 1.3.1. for循环 1.3.2. while循循环 1.3.3. do-wh ...
- go学习笔记接口部分
Go学习笔记 接口 接口定义方法 练习 11.1 simple_interface.go: 练习 11.2 interfaces_poly2.go: 接口嵌套接口 如何判断接口类型 方法一varI.( ...
- Java接口(interface)的概念及使用
在抽象类中,可以包含一个或多个抽象方法:但在接口(interface)中,所有的方法必须都是抽象的,不能有方法体,它比抽象类更加"抽象". 接口使用 interface 关键字来声 ...
最新文章
- 可视化神经网络的网络结构并保存
- JQuery进阶学习
- Codevs 1049 棋盘染色
- 防止多重启动之调用Api [收集2005090201]
- 全国计算机等级考试题库二级C操作题100套(第82套)
- ASP.Net Core 3.1 中使用JWT认证
- NGINX 配置超时时间
- (译)2019年前端性能优化清单 — 上篇
- 利用ACS实现AAA服务的搭建
- 数字图像处理第三版中文版部分答案-冈萨雷斯
- Oxygen XML Editor Professional文档的强大工具
- UIUC 云计算概念:SWIM协议笔记
- 【python游戏】新的一年快来变身兔兔战士打败獾守护兔兔吧~
- Android如何快速创建启动动画
- 在Unity3D中使用泛型(上)
- These are the first 50 documents matching your search, refine your search to see others
- LeetCode 41
- 烟台大学—贺利坚的计算机课程教学链接
- Altium designer 备注手册
- 两种不同结构的永磁永磁同步电机特点说明——表贴式和内置式