SystemVerilog之接口详解

1.入门实例

测试平台连接到 arbiter的例子:包括测试平台, arbiter仲裁器, 时钟发生器 和连接的信号。

ㅤㅤㅤ ㅤ ㅤㅤㅤㅤㅤ在这里插入图片描述

Arbiter里面可以自定义发送的权重, 是轮询还是自定义

grant表示仲裁出来的是哪一个,也即只有0,1,因此图中grant的取值只有00 01 10 不可能出现11。

grant_valid表示grant是否有效。

  • 使用端口

    • 顶层连接
    module top;logic[1:0] grant, request;logic grant_valid;bit clk,rst;always #5 clk=~clk;arb_port a1(grant, grant_valid, request, rst, clk);test t1(grant, grant_valid, request, rst, clk);
    endmodule
    
    • 仲裁器模型
    module arb_port(output logic [1:0] grant,output logic grant_valid,input logic [1:0] request,input logic rst,input logic clk);…always@(posedge clk or posedge rst) beginif(rst)grant <=2'b00;else…end
    endmodule
    
    • 测试平台
    module test(input logic [1:0] grant,input logic grant_valid,output logic [1:0] request,input logic rst,input logic clk);initial begin@(posedge clk) request <=2'b01;// 驱动了request01$display("@%05: Drove req=01",$time);repeat(2) @(posedge clk )if(grant_valid &&(grant!=2'b01))// 通常情况下 request是01,那么grant也是01$display("@%0t:a1:grant!=2’b01",$time);…$finish;end
    endmodule
    

这种方法的缺点就是若DUT arb_port的端口需要改变,在test和top中的声明都要改变。

在真实的设计中, 往往含有数百个端口信号,因此,sv中推荐使用一种interface的结构。

2.接口定义

使用接口简化连接。

逻辑设计日益复杂,模块之间的通信必须分割成独立的实体。

SV使用接口来连接不同模块。接口可以看作一捆智能连线,它连接了DUT和验证平台, 它包括了连接,同步(clocking block)。

时钟可以是接口的一部分或者是一个独立的端口。

ㅤㅤㅤ ㅤㅤㅤ ㅤㅤㅤ 在这里插入图片描述

  • 接口声明
interface arb_if(input bit clk);logic[1:0] grant,request;logic grant_valid;logic rst;
endinterface
  • 采用接口的顶层模块
module top;bit clk;always #5 clk=~clk;arb_if arbif(clk);// 例化接口arb a1(arbif);    // 连接DUTtest t1(arbif);   // 连接tb
endmodule:top

若仲裁器的端口无法修改为接口,则需要连接验证人员自己定义的接口到端口上:

module top;bit clk;always #5 clk=~clk;arb_if arbif(clk); 							//例化接口arb_port a1(.grant(arbif.grant), 			//连接DUT.grant_valid(arbif.grant_valid),.request(arbif.request),.rst (arbif.rst),.clk (arbif.clk));test t1(arbif); 							//连接tb
endmodule:top
  • 使用接口的仲裁器,接口信号必须使用非阻塞赋值来驱动
// arbif是例化名称	
module arb(arb_if arbif);…always@(posedge arbif.clk or posedge arbif.rst);beginif(arbif.rst)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:frant!=2'b01",$time);$finish;end
endmodule:test

问题:上述的接口定义中没有指明方向

interface arb_if( input bit clk);logic[1:0] grant,request;logic grant_valid;logic rst;
endinterface

没有指定方向,默认是inout,引入modport给信号分组,可以根据不同的module去定义不同的端口方向

一般情况下TB与DUT端口方向相反,除了clk与rst复位信号

例:使用modport结构将信号分组并指定方向

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

使用时钟同步块将request与grant优化后:

interface arb_if(input bit clk);logic [1:0] grant, request;logic rst;// 声明一个时钟模块cbclocking cb @(posedge clk);output request;input grant;endclocking// 调用cbmodport TEST (clocking cb,output rst);modport DUT (input request, rst, output grant);
endinterface

则module定义的时候端口例化就变成:注意观察括号中的变化

module arb(arb_if.DUT arbif);…
endmodule
module test(arb_if.TEST arbif); …
endmodule
module monitor(arb_if.MONITOR arbif); …
endmodule

通常情况下,还可以去monitor监视上面各种信号的行为

module monitor(arb_if.MONITOR arbif);always@(posedge arbif.request[0]) begin$display("@%0t:request[0] asserted",$time);@(posedge arbif.grant[0])$display("@%0t:grant[0] asserted",$time);endalways@(posedge arbif.request[1]) begin$display("@%0t:request[1] asserted",$time);@(posedge arbif.grant[1])$display("@%0t:grant[1] asserted",$time);end
endmodule

优缺点

  • 优点:
  1. 便于设计重用;
  2. 可以替代原来需要在模块或者程序中重复声明并且位于代码内部的一系列信号,减少连接错误的可能性
  3. 要增加一个新信号时,,只需要在接口中声明一次,不需要在更高层的模块层声明, 进一步减少错误;
  4. modport允许一个模块将接口的一系列信号捆绑到一起,为信号指定方向;
  • 缺点:
  1. 对于点对点的连接,使用modport跟使用信号列表的端口一样冗余(A与B之间如果就例化了一次,就会冗余);
  2. 必须同时使用信号名和接口名,会使模块变得更加冗长;
  3. 如果连接两个模块使用的是一个不会被重用的专用协议,使用接口需要做比端口连线更多的工作;
  4. 连接两个不同的接口很困难;一个新的接口可能包含了现有接口的所有信号并新增了信号,需要拆分独立的信号并正确的驱动;

总之:瑕不掩瑜,尽量使用interface,方便后续维护修改。

端口能做的,接口90%都能做,模块里面可以例化模块,模块可以例化接口,接口可以例化接口,但是接口不能例化模块

实例:根据design,设计出test bench,分别用端口连接、接口连接实现,并体会他们的异同

  1. design

    module arb_port(output logic [1:0] grant, output logic grant_valid,input logic [1:0] request,input logic rstn,input logic clk);logic pri;// 时序逻辑always_ff @(posedge clk or negedge rstn)begin// 默认两个端口0,1,在rst复位之后,0端口的优先级高if(!rstn)pri <=0;// 每来一个clock,pri就发生翻转elsepri<=~pri;end// 组合逻辑always_comb begin// 按位或,只要request等于10 01 11,grand_valid都等于1,也即grand有效grant_valid = |request;if(request== 2'b01 || request==2'b10)grant = request;// request同时为1,就会比较优先级else if (request==2'b11)// 无优先级的caseunique case(pri)// 比较优先级,优先级为0,就输出0口1'b0: grant = 2'b01;1'b1: grant = 2'b10;endcaseelse begingrant_valid = 0;grant =0;endend
    endmodule
    
  2. 使用端口

    module test(input logic [1:0] grant,input logic rant_valid,output logic [1:0] request,input logic rstn,input logic clk);initial begin@(posedge clk) request <=2’b01;$display("@%05: Drove req=01",$time);repeat(2) @(posedge clk )...end
    endmodule
    
  3. 使用接口

    module test(arb_if.TB arbif);initial beginarbif.rstn=1;repeat(2) @(posedge arbif.clk);arbif.rstn=0; // assertrepeat(5) @(posedge arbif.clk);arbif.rstn=1; // release@(posedge arbif.clk) arbif.request <=2'b01;$display("@%05t: Drove req=01",$time);repeat(2) @(posedge arbif.clk);arbif.request <=2'b10;$display("@%05t: Drove req=10",$time);repeat(2) @(posedge arbif.clk);arbif.request <=2'b11;$display("@%05t: Drove req=11",$time);repeat(2) @(posedge arbif.clk);end
    endmodule
    
  4. 定义接口

    interface arb_if(input bit clk);logic [1:0] grant;logic [1:0] request;logic grant_valid;logic rstn;modport TB(input grant_valid,grant,clk,output request,rstn);modport DUT(input request,rstn,clk,output grant_valid,grant);
    endinterface
    
  5. 顶层模块

    module top;bit clk;always #5 clk = ~clk;arb_if arbif(clk);test u_test(arbif);// 由于端口无法修改为接口,因此手动连接定义的接口到端口上arb_port u_arb(.grand(arbif.grand),.grand_valid(arbif.grand_valid),.request(arbif.request),.rstn(arbif.rstn),.clk(clk));
    endmodule
    

在编译器中编译的顺序是有要求的,也即要先编译底层,最后再编译top顶层。同时,使用接口的时候需要确保在模块与程序块之外声明接口变量例如``include “arb_if.sv”`

3.接口同步

接口信号采样与驱动就使用到了接口同步

在RTL仿真时候会遇到信号竞争问题也即(Delta cycle仿真异常行为)。

例:b的值应该取clk上升沿之前的值0,但是却取了1

ㅤㅤㅤ ㅤㅤㅤ ㅤㅤㅤ在这里插入图片描述

为了防止Deltal cycle的发生,因此我们采用clocking block(只能在testbench里面用)

在clocking block,所有信号的采样和驱动,都是跟时钟同步的(但要注意采样与驱动的不同)

interface arb_if(input bit clk);logic [1:0] grant, request;logic reset;// 声明一个时钟模块cbclocking cb @(posedge clk);output request;input grant;endclocking// 调用cbmodport TEST (clocking cb,output reset);modport DUT (input request, reset, output grant);
endinterface

通过clocking block完成同步,也即每一步操作都是跟clock对齐的,这样就完成request与grant的同步

program automatic test(bus_if.TB bus);initial begin@bus.cb; //在时钟块的有效时钟沿触发repeat(4) @bus.cb; //等待4个有效时钟沿@bus.cb.grant; //监测grant信号的变化(上升,下降)@(posedge bus.cb.grant); //监测grant信号的上升沿@(negedge bus.cb.grant); //监测grant信号的下降沿wait (bus.cb.grant==1); // 监测一个电平值, 若监测不到, 则一直等待@(posedge bus.cb.grant or negedge bus.reset); //监测grant上升沿,reset的下降沿end
endprogram

注意:在测试模块的时钟块中,使用modport的时候,任何同步接口信号都必须加上接口名(arbif)时钟名称(cb),例如request信号,要写成arbif.cb.request

4.接口采样与驱动

  • 接口采样:当从时钟块中读取信号的时候,是在时钟沿之前得到的采样值

    test程序块对clocking cb中的输入信号grant进行采样。 采样输出为arbif.cb.grant

    // interface中定义的clocking block
    interface arb_if(input bit clk);logic [1:0] grant, request;logic reset;// 声明一个时钟模块cbclocking cb @(posedge clk);output request;input grant;endclocking// 调用cbmodport TEST (clocking cb,output reset);modport DUT (input request, reset, output grant);
    endinterfaceprogram test(arb_if.TEST arbif);initial begin$monitor("@%0d: grant=%h", $time, arbif.cb.grant);#50;end
    endprogrammodule arb(arb_if.DUT arbif);initial beginarbif.grant = 1; // @ 0ns#12 arbif.grant = 2; // @ 12ns#18 arbif.grant = 3; // @ 30nsend
    endmodule
    

    DUT的信号输出grant,clock block的cb.grant输出如波形所示。

ㅤㅤㅤ ㅤㅤㅤ在这里插入图片描述

在30ns处,DUT的grant的值在时钟沿跳变,同时TEST的cb.grant也在该时钟沿触发输出,但此时它采样的值还是该时刻之前的值2。

简而言之:采样拿旧值

  • 接口驱动:在test中驱动同步信号arbif.cb.request ,在DUT中监测arbif.request的输出

    program test(arb_if.TEST arbif);initial begin#7 arbif.cb.request <= 3;  // @ 7ns#10 arbif.cb.request <= 2; // @ 17ns#13 arbif.cb.request <= 1; // @ 30ns#15 $finish;end
    endprogrammodule arb(arb_if.DUT arbif);initial$monitor("@%0t: req=%h", $time, arbif.request);
    endmodule
    

    test中arb.cb.request,DUT中request的波形如图:

ㅤㅤㅤ ㅤㅤㅤ在这里插入图片描述

注意:30ns处arb.cb.request的变化立刻在上升沿被传送到arb.request上。因为在clocking block中输出信号的默认延迟为#0,软件在编译时, clocking block中 的输出信号要晚于被采样信号的变化,但在波形上观察不出来。

驱动也即就是test的输出,也即给DUT去使用的,由于需要立刻赋值给DUT,因而驱动是拿新值

简而言之:驱动拿新值

  • 总结:在clocking block中,采样(input)和驱动(output)信号遵循如下原则:

    同步后的采样信号,都是前一个状态的值。

    同步后的驱动信号,都是当前状态的值。

到底是驱动还是采样,是由clock中的定义的信号方向决定的,而clocking block只能用于TB,因此:

在Test中,input就是对DUT的输出进行采样,output就是对DUT进行驱动,模拟了电路的一种属性

例如按下reset按钮,就必须立刻生效,如果要采样DUT的output的值的时候,就需要使用clocking block去采样。

5.接口中的双向信号

双向信号inout:inout必须定义为wire

interface master_if(input bit clk);wire[7:0] data;clocking cb@(posedge clk);inout data;endclockingmodport TEST(clocking cb);
endinterface
program test(master_if mif);initial beginmif.cb.data <='z; 	   //高阻态@mif.cb;$display(mif.cb.data); //从总线读取@mif.cb;mif.cb.data <=7'h5a;   //驱动总线@mif.cb;mif.cb.data <='z; 	   //释放总线end
endprogram

由于SV的用户参考手册中没有明确定义如何驱动接口中的异步双向信号, 故可用以下两种方法:

  1. 连续赋值语句

  2. 虚接口 virtual interface

6.为什么在程序块中不能使用always块

testbench中,程序的运行是有序性的:初始化,驱动激励信号,收取设计对激励的反馈,最后结束。当最后一个initial模块结束后,这个仿真也结束了,就像执行了$finish一样。而 always 语句是没有结束的,需要$exit来指定结束;

如果确实需要用一个always块, 可以使用**initial forever**来完成相同的事情; 所以initial forever在testbench中可以使用,功能类似于always。

program块中不支持always语句(编译会报错)

在program可以通过initial forever来代替,后续一般会使用initial forever去产生clock。

7.时钟发生器

program bad_generator (output bit clk, out_sig);bit clk=0, out_sig=0;initialforever #5 clk <= ~clk;initial// 这里输出了两个时钟,这个out_sig看起来是clk的二分频。forever @(posedge clk)out_sig <= ~out_sig;
endprogram

上例将时钟的产生定义到了program中,这样就会产生速度问题,时钟的翻转和信号变化同时的,应该判定谁的变化在前?

可能会引起竞争状态。 所以应该在module或者class中声明clk

module clock_generator (output bit clk);bit clk = 1;always #5 clk = ~clk; // Use blocking assignment
endmodule

8.虚接口

interface 封装了modue的端口(ports)、方向(modports)、同步关系 ( clocking block)interface 简化了模块之间的连接,但是无法很好地适用于基于OOP的测试平台,无法在program ,class中进行实例化

为了解决这个问题, System Verilog引入了virtual interface的概念。 使用virtual interface是为了消除绝对路径,尽可能的减少验证代码的大面积修改。绝对路径:以前在TB里面引用都是接口.xxx等,使用虚接口之后,减少大面积的修改。

virtual interface的本质是指针,是指向interface的指针,即virtual interface是可以在class中实例化的数据类型,使用virtual interface可与被测设计(DUT)进行间接地通信,而无需使用层次结构引用。

ㅤㅤㅤ在这里插入图片描述

如图所示:interface将测试平台与DUT分开。 virtual interface在TB的不同位置操纵一组虚拟信号,而不是直接操纵实际的信号。

在测试平台使用virtual interface时,需要满足以下3个要求:

  1. 实例化的接口必须正确连接到DUT。

    // 创建一个interface简化与DUT的连接
    interface counter_if (input logic clk);logic load_valid;logic [3:0]load_value;
    endinterfacemodule tb_top;logic rstn,clk;logic [3:0]out;// 实例化接口counter_if dutif(clk);counter u_counter (.resetn(rstn),.clk(clk),.load_valid(dutif.load_valid),.load_value(dutif.load_value),.q(out));
    endmodule
    
  2. 必须在类中声明virtual interface句柄,并且有相应驱动。

    // 创建一个transaction用来生成随机激励
    class transaction;rand logic load_valid;rand logic [3:0]load_value;
    endclass// 创建一个驱动激励到DUT上
    class driver;virtual counter_if vif;transaction tr;function new(input virtual counter_if vif);this.vif=vif;endfunctiontask run (int n=10);for(int i=0;i<n;i++) begintr=new();assert(tr.randomize());$display("tr.load_valid=%d,tr.load_value=%d", tr.load valid, tr.load_value);@(posedge vif.clk) beginvif.load_valid <= tr.load_valid;vif.load_value <= tr.load_value;endendendtask
    endclass
    
  3. 必须将virtual interface指向实例化的interface

    counter_if dutif(clk);driver my_driver; // create my_driver
    initial beginmy_driver = new(dutif);
    end
    

实际案例:

counter_if.sv:定义一个接口,简化与DUT的连接。

interface counter_if (input logic clk);logic load_valid;logic [3:0]load_value;
endinterface

transaction.sv:定义了一个类,用来生成随机激励。

class transaction;rand logic load_valid;rand logic [3:0]load_value;
endclass

counter.sv:待测类型DUT,q赋初值之后就会不断的自加

module counter(input logic resetn,input logic clk,input logic [3:0] load_value,input logic load_valid, output logic [3:0] q
);always_ff @(posedge clk or negedge resetn)beginif(!resetn)q<= 4’d0;else if (load_valid)q<= load_value;elseq<= q+1;end
endmodule

driver.sv:驱动激励到DUT上

class driver;virtual counter_if vif;transaction tr;function new(input virtual counter_if vif);this.vif=vif;endfunction// 驱动interfacetask run (int n = 10);for(int i=0;i<n;i++) begintr=new();assert(tr.randomize());$display("tr.load_valid=%d,tr.load_value=%d", tr.load valid, tr.load_value);@(posedge vif.clk) begin// 通过驱动虚接口来驱动DUTvif.load_valid <= tr.load_valid;vif.load_value <= tr.load_value;endendendtask
endclass

tb_top.sv:用来将以上文件整合

module tb_top;logic clk,rstn;logic [3:0]out;counter_if dutif(clk);driver my_driver;// 接口与interface进行连接counter u_counter (.resetn(rstn),.clk(clk),.load_valid(dutif.load_valid),.load_value(dutif.load_value),.q(out) );initial begin// 连接接口my_driver=new(dutif);//实例化驱动,使虚接口句柄指向interfacerepeat(2)@(posedge clk);@(posedge rstn);repeat(5)@(posedge clk);my_driver.run(20);endinitial beginclk=1'b0; forever #5 clk=~clk;end// 驱动rstninitial beginrstn=1; repeat(2) @(posedge clk);rstn=0; repeat(5) @(posedge clk);rstn=1; repeat(50) @(posedge clk);$finish;end
endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/98002.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第六阶|见道明心的笔墨(上)从书法之美到生活之美——林曦老师的线上直播书法课

如果你有需要&#xff0c;可以找我的&#xff0c;我这边有老师的所有课程 如果你有需要&#xff0c;可以找我的&#xff0c;我这边有老师的所有课程

解决xss转义导致转码的问题

一、xss简介 人们经常将跨站脚本攻击&#xff08;Cross Site Scripting&#xff09;缩写为CSS&#xff0c;但这会与层叠样式表&#xff08;Cascading Style Sheets&#xff0c;CSS&#xff09;的缩写混淆。因此&#xff0c;有人将跨站脚本攻击缩写为XSS。跨站脚本攻击&#xff…

时序预测 | MATLAB实现SA-ELM模拟退火算法优化极限学习机时间序列预测

时序预测 | MATLAB实现SA-ELM模拟退火算法优化极限学习机时间序列预测 目录 时序预测 | MATLAB实现SA-ELM模拟退火算法优化极限学习机时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现SA-ELM模拟退火算法优化极限学习机时间序列预测 程序设计 完整…

树莓派和windows之间文件传输

方案一&#xff1a;FileZilla 在电脑上下载FileZilla软件并打开&#xff0c;输入配置信息&#xff0c;用户名/密码、树莓派的IP地址,点击“快速连接” 方案二&#xff1a;samba 树莓派安装 samba 软件 sudo apt-get install samba samba-common-bin 修改配置文件 / etc /samba…

ARM体系结构学习笔记:任何算法可通过下面的三种模式组合而成

任何算法可通过下面的三种模式组合而成 条件跳转和无条件跳转 条件命名规则 关于比较的一些哲学问题 汇编实现if else [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R8R5cYTQ-1692236026691)(https://cdn.jsdelivr.net/gh/nzcv/picgo/202201172242…

2.创建小程序

创建 在开发工具中,选择小程序,点击加号 填写小程序信息,模板使用的是TS+Sass 编辑器的工作区 目录结构 项目使用的是ts的模板,目录结构和js的有一点差异,目录结构如下: miniprogram:小程序根目录 —pages:小程序页面目录 ——xxx:页面目录,一个页面对应一个目…

kafka--kafka的基本概念-topic和partition

一、kafka的基本概念-topic和partition 1、topic &#xff08;主题 &#xff09; topic是逻辑概念 以Topic机制来对消息进行分类的&#xff0c;同一类消息属于同一个Topic&#xff0c;你可以将每个topic看成是一个消息队列。 生产者&#xff08;producer&#xff09;将消息发…

项目实战 — 博客系统③ {功能实现}

目录 一、编写注册功能 &#x1f345; 1、使用ajax构造请求&#xff08;前端&#xff09; &#x1f345; 2、统一处理 &#x1f384; 统一对象处理 &#x1f384; 保底统一返回处理 &#x1f384; 统一异常处理 &#x1f345; 3、处理请求 二、编写登录功能 &#x1f345; …

RabbitMq-1基础概念

RabbitMq-----分布式中的一种通信手段 1. MQ的基本概念&#xff08;message queue,消息队列&#xff09; mq:消息队列&#xff0c;存储消息的中间件 分布式系统通信的两种方式&#xff1a;直接远程调用&#xff0c;借助第三方完成间接通信 消息的发送方是生产者&#xff0c…

动物IT

动物是地球上最丰富和多样化的生物群体之一。它们包括鱼类、鸟类、爬行动物、两栖动物和哺乳动物等各种类型。动物在地球上有着不同的生态角色和生活习性。 动物对于维持生态平衡和生态系统的稳定性至关重要。它们在食物链中扮演着重要的角色&#xff0c;通过捕食和被捕食来保…

CentOS6上安装MySQL8与Nginx开机自启

背景 临时在一台华为云的 CentOS6 上安装部署一个业务系统&#xff0c;这里记录下 MySQL 8 与 Nginx 的安装过程中遇到的问题。 CentOS6上安装MySQL8 # 下载 wget http://repo.mysql.com/yum/mysql-8.0-community/el/6/x86_64/mysql-community-common-8.0.19-1.el6.x86_64.r…

第一个ArkTS项目实践-鸿蒙ArkTS

第一个ArkTS项目实践-ArkTS 第一个ArkTS项目实践-ArkTS自定义组件的组成配置属性与布局配置属性布局 改变组件状态循环渲染列表数据代码ToDoItem组件ToDoList页面 效果参考资料 第一个ArkTS项目实践-ArkTS 本篇文章是官网上视频对ArkTS开发实践的第一个视频&#xff0c;主要是引…

通过案例学习pandas计算相关系数

pandas计算相关系数 在数据分析和统计学中&#xff0c;相关系数是一种用于衡量两个变量之间关系强度的统计指标。它可以帮助我们了解两个变量之间的线性关系强度和方向。 Pandas是一个强大的Python库&#xff0c;提供了许多用于数据分析和处理的功能。在本文中&#xff0c;我…

利用POM完成脚本分离实现企业级自动化(POM设计模式+页面的框架封装+测试报告截图)

利用POM完成脚本分离实现企业级自动化&#xff08;POM设计模式页面的框架封装测试报告截图&#xff09; 项目-测试-手工测试 项目-测试-手工测试 1.了解需求&#xff1b; 2.编写测试用例&#xff08;开始&#xff09;——功能测试组会去做的事情 3.执行测试用例——发送测试报…

【ES5和ES6】数组遍历的各种方法集合

一、ES5的方法 1.for循环 let arr [1, 2, 3] for (let i 0; i < arr.length; i) {console.log(arr[i]) } // 1 // 2 // 32.forEach() 特点&#xff1a; 没有返回值&#xff0c;只是针对每个元素调用func三个参数&#xff1a;item, index, arr &#xff1b;当前项&#…

Android 9.0 Vold挂载流程解析(上)

前言 我们分2篇文章来介绍Android 9.0中存储卡的挂载流程&#xff0c;本篇文章先介绍总体的挂载模块、Vold进程的入口main函数的详细分析&#xff0c;有了这些基础知识&#xff0c;下一篇中我们再详细介绍收到驱动层消息是怎么挂载和卸载存储卡的&#xff0c;还有framework层如…

vue实现穿梭框,ctrl多选,shift多选

效果图 代码 <template><div class"container"><!--左侧--><div><div class"title">{{ titles[0] }}</div><div class"layerContainer"><div v-for"item in leftLayerArray":key"…

实验三 nfs 服务器环境搭建

nfs 服务器环境搭建 nfs&#xff08;Network File System&#xff09;即网络文件系统&#xff0c;其基于UDP/IP 使用nfs能够在不同计算机之间通过网络进行文件共享&#xff0c;能使使用 者访问网络上其它计算机中的文件就像在访问自己的计算机一样。 【实验目的】 掌握 nfs 环…

Redis专题-秒杀

Redis专题-并发/秒杀 开局一张图&#xff0c;内容全靠“编”。 昨天晚上在群友里看到有人在讨论库存并发的问题&#xff0c;看到这里我就决定写一篇关于redis秒杀的文章。 1、理论部分 我们看看一般我们库存是怎么出问题的 其实redis提供了两种解决方案&#xff1a;加锁和原子操…

空洞卷积学习笔记

文章目录 1. 扩张卷积的提出2. 理解的难点 本片博客的主题思路来自于这篇文章——如何理解Dilated Convolutions(空洞卷积)&#xff0c;但是作者似乎是很久之前写的&#xff0c;文字的排版很混乱&#xff0c;自己来写一个新的。 1. 扩张卷积的提出 Multi-Scale Context Aggre…