System Verilog的接口、程序块与断言解析

接口、程序块与断言

1 接口

1.1 使用接口简化连接

// 接口
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)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);$finishend
endmodule// top模块
module top;bit clk;always #5 clk = ~clk;arb_if arbif(clk);arb a1(arbif);test t1(arbif);
endmodule

1.2 使用modport将接口中的信号分组

在接口中使用modport结构能够将信号分组并指定方向

// 带有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// 接口中使用modport的仲裁器模型
module arb (arb_if.DUT arbif);
...
endmodule// 接口中使用modport的测试平台
module test (arb_if.TEST arbif);
...
endmodule// 接口中使用modport的仲裁器监视模块
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.3 使用时钟块

采样时发生竞争(delta cycle的存在),会导致采样数据错误。为了避免在RTL仿真中发生信号竞争的问题,建议通过非阻塞赋值或者特定的信号延迟来解决同步问题。这里我们介绍使用clocking时钟块来决定信号的驱动和采样的方式。

delta cycle存在的问题:

  • 在RTL仿真时,由于无法确定具体电路的延迟时间,默认情况下时钟驱动电路时会添加一个**无限最小的时间(delta cycle)**的延迟,这个延迟要比最小时间单位精度还要小(可以理解成远小于1ps)。
  • 由于各种可能性,clk与被采样数据之间如果只存在若干个delta-cycle的延迟,那么采样就会出问题。

在这里插入图片描述

在时钟上升沿采样信号,只看vld信号(1->0)就会疑惑采样到的是1还是0,在RTL仿真时,是看不到真实的物理时序信息的,但实际采样到的是1;真实电路对应的时vld_actual信号,它的变化会较clk有一个detal-cycle的延迟,这样看在时钟上升沿采集到的是1。

还有一种方法就是,设置采样vld信号的时间,设置在时钟上升沿之前 #t 采样,这样采出来的数据也是准确的;同样也可以设置信号输出时间,设置在时钟上升沿之后 #t 输出,这样输出的数据也是准确的;

interface chnl_intf(input clk, input rstn);logic [31:0] ch_data; logic        ch_valid;logic        ch_ready;logic [ 5:0] ch_margin;// 定义时钟块clocking drv_ck @(posedge clk);//采样时间default input #1ns output #1ns; //在clk上升沿的前1ns对其进行输入采样,在事件的后1ns进行输出驱动//声明变量方向output ch_data, ch_valid;input ch_ready, ch_margin;endclocking
endinterface

在SystemVerilog中引入时钟块是为了解决在写testbench时对于特定时序和同步处理的要求而设计的。

时钟块是在一个特定的时钟上的一系列同步的信号,它基本上能够将testbench中与时序相关的结构、函数和过程块分开,能够帮助设计人员根据transaction 和 cycle完善testbench,时钟块只能在module、interface或program中声明

// 可置位的二进制计数器
module COUNTER (input Clock, Reset, Enable, Load, UpDn, input [7:0] Data, output reg[7:0] Q);always @(posedge Clock or posedge Reset)if (Reset)Q <= 0;elseif (Enable)if (Load)Q <= Data;elseif (UpDn)Q <= Q + 1;elseQ <= Q - 1;
endmodule// 不采用时钟块的testbench
module Test_Counter;timeunit 1ns;reg Clock = 0, Reset, Enable, Load, UpDn;reg [7:0] Data;wire [7:0] Q;reg OK;// Clock generatoralwaysbegin#5 Clock = 1;#5 Clock = 0;end// Test stimulusinitialbeginEnable = 0;Load = 0;UpDn = 1;Reset = 1;#10; // Should be resetReset = 0;#10; // Should do nothing - not enabledEnable = 1;    #20; // Should count up to 2UpDn = 0;#40; // Should count downto 254UpDn = 1;// etc. ...end// Instance the device-under-testCOUNTER G1 (Clock, Reset, Enable, Load, UpDn, Data, Q);// Check the resultsinitialbeginOK = 1;#9;if (Q !== 8'b00000000)OK = 0;#10;if (Q !== 8'b00000000)OK = 0;#20;if (Q !== 8'b00000010)OK = 0;#40;if (Q !== 8'b11111110)OK = 0;// etc. ...end
endmodule// 采用时钟块的testbench
module Test_Counter_w_clocking;timeunit 1ns;reg Clock = 0, Reset, Enable, Load, UpDn;reg [7:0] Data;wire [7:0] Q;// Clock generatoralwaysbegin#5 Clock = 1;#5 Clock = 0;end// Test program// 将验证部分与设计部分进行隔离(实现方式就是将软件验证部分放置program中)program test_counter;// SystemVerilog "clocking block"// Clocking outputs are DUT inputs and vice versadefault clocking cb_counter @(posedge Clock);default input #1step output #4;output negedge Reset;output Enable, Load, UpDn, Data;input Q;endclocking// Apply the test stimulusinitial begin// Set all inputs at the beginning    Enable = 0;            Load = 0;UpDn = 1;Reset = 1;// Will be applied on negedge of clock!##1 cb_counter.Reset  <= 0;// Will be applied 4ns after the clock!##1 cb_counter.Enable <= 1;##2 cb_counter.UpDn   <= 0;##4 cb_counter.UpDn   <= 1;// etc. ...      end// Check the results - could combine with stimulus blockinitial begin// Sampled 1ps (or whatever the precision is) before posedge clock##1 assert (cb_counter.Q == 8'b00000000);##1 assert (cb_counter.Q == 8'b00000000);##2 assert (cb_counter.Q == 8'b00000010);##4 assert (cb_counter.Q == 8'b11111110);// etc. ...      end// Simulation stops automatically when both initials have been completedendprogram// Instance the counterCOUNTER G1 (Clock, Reset, Enable, Load, UpDn, Data, Q);// Instance the test program - not required, because program will be instanced implicitly.
endmodule

2 程序块

2.1 程序块和时序区域

SystemVerilog 如何把测试平台的事件设计的事件分开调度?
SystemVerilog 引入一种新的时间片的划分方式,如下图所示。

  • 在一个时间片内首先执行的是 Active 区域,在这个区域中运行设计事件,包括 RTL 、门级代码和时钟发生器。
  • 第二个区域是 Observed 区域,执行断言。
  • 接下来就是执行测试平台的 Reactive 区域。注意到时间不是单向地前向流动 —— ObservedReactive 区域的事件可以触发本时钟周期内 Active 区域中进一步的设计事件。
  • 最后就是 Postponed 区域,它将在时间片的最后,所有设计活动都结束后的只读时间段采样信号。

在这里插入图片描述

Active:仿真模块中的设计代码
Observed:执行SystemVerilog断言
Reactive:执行程序中的测试平台部分
Postponed:为测试平台的输入采样信号

// 使用带有时钟块接口的测试平台
program automatic test (arb_if.TEST arbif);
...initial beginarbif.cb.request <= 2'b01;$display("@%0t:Drove req=01",$time);repeat(2) @arbif.cb; // @arbif.cb 语句将等待时钟块给出的有效沿 @(posedge clk)if(arbif.cb.grant != 2'b01)$display("@%0t:a1:grant != 2'b01",$time);end
endprogram : test

2.2 仿真的结束

在verilog中,仿真在调度事件存在时会继续执行,直到遇到 $finish
SystemVerilog新增加了一种结束仿真的方法:SystemVerilog把任何一个程序块都视为含有一个测试,如果仅有一个程序块,那么当完成所有initial块中最后一个语句时,仿真就结束了,因为编译器认为这就是测试的结尾,即使还有模块或者程序块的线程在运行,仿真也会结束。如果存在多个程序块,仿真在最后一个程序块结束时结束,可以执行 $exit 提前中断任何一个程序块。

2.3 程序块(program)中不允许使用 always

在SystemVerilog中,可以在 program 中使用 initial 块,但是不能使用 always 块。SystemVerilog程序比由许多并行执行的块构成的Verilog 更接近C程序,它拥有一个(或多个)程序入口。在一个设计中,一个 always 块可能从仿真的开始就会在每一个时钟的上升沿触发执行。但是一个测试平台的执行过程是经过初始化、驱动和响应设计行为等步骤后结束仿真的。在这里,一个连续执行的 always 模块不能正常工作。
program 中最后一个initial块结束的时候,仿真实际上也就默认结束了,就像执行了 $finish 一样。如果加入了一个always块,它将永远不会结束,这样就不得不明确地调用 $exit 来发出程序块结束的信号。如果确实需要一个always块,可以使用 initial forever 来完成相同的事情。

3 断言

可以使用SystemVerilog断言(SVA)在设计中创建时序断言。断言的例化跟其他设计块的例化相似,而且在整个仿真过程中都是有效的。仿真器会跟踪哪些断言被激活,这样就可以在此基础上收集功能覆盖率的数据。

3.1 立即断言

测试平台的过程代码可以检查待测设计的信号值和测试平台的信号值,并且在存在问题的时候采取相应的行动。
例如,如果产生了总线请求,期望在两个时钟周期后产生应答,可以使用一个if语句来检查这个应答。

// 使用一个if语句检查一个信号
bus.cb.request <= 1;
repeat(2) @bus.cb;
if(bus.cb.grant != 2'b01)$display("Error, grant != 1");// 简单的立即断言
bus.cb.request <= 1;
repeat(2) @bus.cb;
a1: assert (bus.cb.grant == 2'b01);
// ----------------------------------
// 如果正确地产生了grant信号,那么测试继续执行,如果信号不符合期望值,仿真器将会给出一个如下所示的信息:
// "test.sv",7:top.t1.a1:started at 55ns failed at 55ns
// offending '(bus.cb.grant == 2'b1)'
// 该消息指出,在test.sv文件中的第七行,断言top.t1.a1在55ns开始检查信号bus.cb.grant,但是立即检查出了错误。

3.2 定制断言行为

一个立即断言有可选的then和else分句,如果想改变默认的消息,可以添加自己的输出信息。

// 在立即断言中创建一个定制的错误消息
a1: assert (bus.cb.grant == 2'b01)
else $error("Grant not asserted");

SystemVerilog 有四个输出消息的函数:$info, $warning, $error$fatal。这些函数仅允许在断言内部使用,而不允许在过程代码中使用。

// 使用then子句来记录断言何时成功完成
a1: assert (bus.cb.grant == 2'b01)grants_received++;  // 另一个成功的结果
else$error("Grant not asserted");

3.3 并发断言

另一种断言就是并发断言,可以认为它是一个连续运行的模块,它为整个仿真过程检查信号的值。需要在断言内指定一个采样时钟。下面是一个检查仲裁器request信号的断言。request信号除了在复位期间,其他任何时候都不能是X或Z。

interface arb_if(input bit clk);logic [1:0] grant, request;logic rst;property request_2state;@(posedge clk) disable iff(rst);$isunknown(request) == 0; // 确保没有Z或者X值存在endpropertyassert_request_2state: assert property(request_2state);
endinterface

3.4 语法之序列

序列由sequence… endsequence声明
功能特性经常由有序的行为构建,sequence功能提供了一种能力来构建和处理有序的行为。
在一系列的布尔逻辑表达式中,如果每个布尔表达式的计算都为真,那么关于这个序列的断言为真,否则为假。

sequence s1;  //无参数@(posedge clk) a ##1 b ##1 c; //##1指的是延时一个周期	
endsequence //上面的意思是先a是1,一个周期后b是1,一个周期c是1sequence s2(data,en); //带参数@(posedge clk)(!a && (data == data_bus) ##1 c[0:3] == en )
endsequence

SVA也内嵌了边缘表达式,以便用户监视信号值从一个时钟周期到另一时钟周期的跳变。这使得用户能检查边沿敏感的信号(前后信号不一致才是属于跳变)

  • $rose(boolean expression or signal name) 当信号/表达式为1时返回真。
  • $fell(boolean expression or signal_ name) 当信号/表达式为0时返回真。
  • $stable(boolean"expression or signal_ name) 当信号/表达式不发生变化时返回真。

SVA语法—时钟关系的序列
很多时候,我们关心的是检查需要几个时钟周期才能完成的事件。也就是所谓的“时序检查”。在SVA中,时钟周期延迟用"#" 来表示。例如,#3表示3个时钟周期。举个例子:

sequence s1;@(posedge clk) a ##2 b;
endsequence 	

序列s1检查信号"a"在一一个给定的时钟上升沿是否为高电平:
如果信号"a"不是高电平,序列失败,断言失败。
如果信号"a"在任何一一个给定的时钟上升沿为高电平,信号"b” 在两个时钟周期后为高电平,则断言成功。
如果信号"a"在任何一一个给定的时钟上升沿为高电平,信号"b" 在两个时钟周期后为不为高电平,断言失败。
在仿真后结果显示中,成功的序列总是标注在序列开始的位置

3.5 语法之属性

许多序列可以有序地组合起来生成更复杂的序列。SVA 提供了一个关键词property 来表示这些复杂的有序行为。属性(property)的基本语法是:

property name_ of_ property;
; or
;
endproperty

属性是在模拟过程中被验证的单元。它必须在模拟过程中被断言来发挥作用。 SVA提供了关键"assert"来检查属性。断言(assert)的基本语法是:
assertion_ name: assert property (property_ name);

interface arb_if(input bit clk);logic [1:0] grant, request;logic rst;property request_2state;@(posedge clk) disable iff(rst);$isunknown(request) == 0; // 确保没有Z或者X值存在endpropertyassert_request_2state: assert property(request_2state);
endinterface

3.6 语法之时钟定义

// 定义一个序列并不能发挥作用,它必须被断言才能发挥作用
// SVA在序列、 属性甚至一个断言的语句中都可以定义时钟。
sequence s5;a ##2 b;
endsequenceproperty p5;@(posedge clk) s5;
endpropertya5: assert property(p5);

通常情况下在sequence描述行为,在property描述时钟

3.7 语法之禁止属性

属性可以禁止发生。即我们期望属性永远为假,当属性为真时,断言失败。
序列s6检查当信号"a"在给定的时钟上升沿为高电平,那么两个时钟周期以后,信号"b"不允许是高电平。关键词"not" 用来表示属性应该永远不为真。

sequence s6;@(posedge clk) a ##2 b;
endsequenceproperty p6not s6;
endpropertya6: assert property(p6);

3.8 语法之执行块

SystemVerilog 语言被定义成每当一个断言检查失败,模拟器在默认情况下都会打印出一条错误信息。模拟器不需要对成功的断言打印任何东西。读者同样可以打印自定义自定义的成功或失败信息。

property p7@(posedge clk) a ##2 b;
endpropertya7: assert property(p7)$display("Property p7 succeeded\n");
else$display("Property p7 failed\n");

3.9 语法之蕴含操作

对于@(posedge clk) a #2 b这样的属性,它在每个时钟上升沿检查信号"a" 是否为高。寻找是否为一个断言的有效开始。
如果信号"a"在给定的任何时钟上升沿不为高,检验器将产生一个错误信息。这并不是一个有效的错误信息因为我们不只关心a,更加关心a和b的关系。这个错误只表明这个时钟周期没有得到有效起始点。它们会在一段时间内产生大量的错误信息。

蕴含
基于以上问题,SVA提供了蕴含操作。
蕴含等效于一个if-then结构。蕴含的左边叫作“先行算子”,右边叫作"后续算子”。当先行算子成功时,后续算子才会被计算。如果先行算子不成功,那么整个属性就默认地被认为成功。这叫作"空成功”
蕴含结构只能被用在属性定义中,不能在序列中使用。

蕴含分为两类:交叠蕴含和非交叠蕴含。
交叠蕴含用符号"|->” 表示。如果先行算子匹配,在同一个时钟周期计算后续算子表达式。例如:

property p8;@(posedge clk) a |-> b;
endpropertya8: assert property(p8);

当信号"a" 为高,而且信号"b" 在同一个时钟沿也为高,这是一个真正的成功。若信号"a"不为高,断言默认自动成功,称为空成功。信号"a" 为高且,并且在同一个时钟沿信号"b" 未能检测为有效的高电平,则断言失败。

非交叠蕴含用符号(“I=>”)表示。如果先行算子匹配,那么在下-一个时钟周期计算后续算子表达式。后续算子表达式的计算总是有一个时钟周期的延迟。 例如:

property p9;@(posedge clk) a|=> b;
endpropertya9: assert property(p9);

3.10 语法之时序窗口

SVA的延迟可以支持固定的正延迟,也可以支持一个时间窗口。例如:

property p10@(posedge clk) (a && b) |-> ##[1:3] c;
endproperty
// 等价于
// (a && b) |-> ##1 c 或
// (a && b) |-> ##2 c 或
// (a && b) |-> ##3 c 

p10先行算子在任何给定的时钟上升沿为真,那么在接下去的1~3周期内,信号"c" 应该至少在一个时钟周期为高,SVA允许使用时序窗口来匹配后续算子。时序窗口表达式左手边的值必须小于右手边的值。每声明一个时序窗口,就会在每个时钟沿上触发多个线程来检查所有可能的成功。p10 实际上展开了三个线程。

3.11 语法之ended结构

默认情况下,多重sequence的组合是以sequence的起始时间作为同步标志的,就是以序列的起始点作为同步点,来组合成时间上连续的检查。
SVA提供ended结构以sequence的结束时间作为序列同步点。关键字ended存储一个反映在指定时钟处序列是否匹配成功的布尔值。
ended代表匹配的完成,是匹配的结束点,而不是匹配的起点。

默认情况下,多重sequence的组合是以sequence的起始时间作为同步标志的,就是以序列的起始点作点作为同步点,来组合成时间上连续的检查。SVA还提供了另一种使用序列的结束点作为同步点的连接机制。

sequence s11a;@(posedge clk) a ##1 b;
endsequencesequence s11b;@(posedge clk) c ##1 d;
endsequenceproperty p11a;s11a |=> s11b;
endpropertyproperty p11b;s11a.ended |-> ##2 s11b.ended;
endpropertya11a: assert property(p11a);
a11b: assert property(p11b);

在这里插入图片描述

3.12 语法之$past构造

SVA提供了一个内嵌的系统任务$past, 它可以得到信号在几个时钟周期之前的值。在默认情况下,它提供信号在前一个时钟周期的值。结构的基本语法如下:
$past (signal name, number of clock cycles)
这个任务能够有效地验证设计到达当前时钟周期的状态所采用的通路是正确的。

property p12;@(posedge clk) (c && d) |-> ($past ((a  && b),2)==1'b1);
endproperty
a12: assert property(p12);

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

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

相关文章

Unity判断某个材质是否拥有某张贴图

在Unity中&#xff0c;一个材质是唯一的&#xff0c;也就是实例&#xff0c;当我们打开Debug面板时&#xff0c;就可以看清楚材质的具体信息。 其中SvaedProperties就是材质保存的属性&#xff0c;当然贴图也是属性&#xff0c;也就是TexEnvs下的属性 当然&#xff0c;要判断某…

ROS2从入门到精通1-1:详解ROS2话题通信机制与自定义消息

目录 0 专栏介绍1 话题通信模型2 话题模型实现(C)3 话题模型实现(Python)4 自定义消息 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握ROS2底层基本分布式原理&#xff0c;并具有机器人建模和应用ROS2进行实际项目的开发和调试的工程能力。 &#x1f680;详情&a…

正则表达式与re模块

目录 正则表达式 简介 语法&#xff1a; 常用元字符&#xff1a; 量词: 贪婪匹配和惰性匹配&#xff1a; re模块 简介&#xff1a; 常用的几个模块&#xff1a; 1.findall 2.search 3.finditer 4.compile 案例展示&#xff1a; 需求&#xff1a; 思路分析&#…

code摘录日记[矩阵变元素,变列向量,3D表面图,table行列设置] Matlab

矩阵变元素&#xff0c;变列向量 W1(Z1 < Z2) nan; % Z1,Z2 all matrix,Only plot points where Z1 > Z2;Z1 < Z2位置值填为NaNx x(:); % Now x is a 30-by-1 vector; matrix变列vector技巧3D表面图 hand figure; % Handle to the figure, for more plotting later…

彻底学会系列:一、机器学习之梯度下降(1)

1 梯度下降概念 1.1 概念 梯度下降是一种优化算法&#xff0c;用于最小化一个函数的值&#xff0c;特别是用于训练机器学习模型中的参数&#xff0c;其基本思想是通过不断迭代调整参数的值&#xff0c;使得函数值沿着梯度的反方向逐渐减小&#xff0c;直至达到局部或全局最小…

python网络编程:通过socket实现TCP客户端和服务端

目录 写在开头 socket服务端&#xff08;基础&#xff09; socket客户端&#xff08;基础&#xff09; 服务端实现&#xff08;可连接多个客户端&#xff09; 客户端实现 数据收发效果 写在开头 近期可能会用python实现一些网络安全工具&#xff0c;涉及到许多关于网络…

供电系统分类详解

一、供电系统分类 电力供电系统一般有5种供电模式&#xff0c;常用的有&#xff1a;IT系统&#xff0c;TT系统&#xff0c;TN系统&#xff0c;其中TN系统又可以分为TN-C&#xff0c;TN-S&#xff0c;TN-C-S。 1、TN-C系统&#xff08;三相四线制&#xff09; 优点: 该系统中…

Hadoop大数据应用:NFS网关 连接 HDFS集群

目录 一、实验 1.环境 2.NFS网关 连接 HDFS集群 3. NFS客户端挂载HDFS文件系统 二、问题 1.关闭服务报错 2.rsync 同步报错 3. mount挂载有哪些参数 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构软件版本IP备注hadoop NameNode &#xff08;…

【Mysql基础】查询01-去重、连接字符、模糊查询、通配符、检索表的结构信息

这里写目录标题 1 去重 distinct2 连接字符 concat(str1,str2,...)3 模糊查询3.1 like 包含3.2 通配符3.3 between and3.4 in3.5 is null 4 安全等于 <>5 检索表的结构信息 desc6 课后练习 1 去重 distinct 使用 DISTINCT 关键字&#xff0c;可以从结果集中去除重复的行…

Mac屏幕录制编辑软件

以下是一些Mac平台上受到推荐和好评的屏幕录制编辑软件&#xff1a; OBS Studio&#xff08;免费且开源&#xff09;&#xff1a; OBS 是一款功能强大的免费屏幕录制工具&#xff0c;不仅限于游戏直播&#xff0c;也适用于各种屏幕录制需求。它允许用户捕获屏幕、摄像头、音频&…

用c++实现装箱问题、数字回转方阵

3.4.1 装箱问题 【问题】有一个工厂制造的产品形状都是长方体&#xff0c;一共有6种型号,每种型号长方体的长和宽分别是11、22、33、44、55、66,高都是h。这些产品使用统一规格的箱子进行包装&#xff0c;箱子的长、宽和高分别是6、6和h。对于每个订单工厂希望用最少的箱子进行…

【蓝屏分析】WHEA_UNCORRECTABLE_ERROR 问题分析与解决

背景信息 电脑名字电脑类型厂商使用时间magicbook14 2020款 R5 4500U笔记本电脑荣耀HONOR3年9个月 内存CPUGPU硬盘焊死在主板上焊死在主板上集显PCIe 4.0 NVMe M.2 固态 软硬件错误源确定 电脑莫名频繁随机蓝屏&#xff0c;由于在软件环境上无迹可寻推测是硬件问题 蓝屏画面…

Windows系统部署hMailServer邮件服务结合内网穿透实现公网收发邮件

文章目录 前言1. 安装hMailServer2. 设置hMailServer3. 客户端安装添加账号4. 测试发送邮件5. 安装cpolar6. 创建公网地址7. 测试远程发送邮件8. 固定连接公网地址9. 测试固定远程地址发送邮件 前言 hMailServer 是一个邮件服务器,通过它我们可以搭建自己的邮件服务,通过cpola…

运动想象 (MI) 迁移学习系列 (9) : 数据对齐(EA)

运动想象迁移学习系列:数据对齐&#xff08;EA&#xff09; 0. 引言1. 迁移学习算法流程2. 欧式对齐算法流程3. 与RA算法进行对比4. 实验结果对比5. 总结欢迎来稿 论文地址&#xff1a;https://ieeexplore.ieee.org/abstract/document/8701679 论文题目&#xff1a;Transfer Le…

数据结构:链式二叉树

对于二叉树而言,如果不是完全二叉树,就不再适合用数组存储了 二叉树结构 typedef struct BinTreeNode {int val;struct BinTreeNode* left;struct BinTreeNode* right; }BTNode; 二叉树的遍历 顺序 访问顺序(n NULL) 1.前序 根,左子树…

软考81-上午题-【面向对象技术3-设计模式】-行为型设计模式01

一、行为型设计模式一览 二、责任链模式 2-1、意图 使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处理它为止。 1-2、结构 1-3、代码实现 1-4、适…

3D产品配置器能为企业的客户带来什么好处?

3D产品配置器能够为企业的客户带来多重好处&#xff0c;提升他们的整体购物体验和满意度。 主要优势分析&#xff1a; 1、 提升购物体验&#xff1a;3D产品配置器通过提供交互式的3D可视化体验&#xff0c;使客户能够从不同角度查看和理解产品&#xff0c;从而提升他们的购物体…

银行信息系统应用架构导论-引用

一级目录二级目录金融标准和参考文档一、银行企业级应用系统架构规划企业级应用系统架构规划《金融科技发展规划&#xff08;2022-2025年&#xff09;&#xff08;2022年1月中国人民银行印发&#xff09;》 《关于银行业保险业数字化转型的指导意见&#xff08;2022年1月中国银…

Python图像处理【23】分布式图像处理

分布式图像处理 0. 前言1. Dask 简介2. 使用 Dask 进行分布式图像处理2.1 将 RGB 图像块转换为灰度图像块2.2 使用分布式 Sobel 滤波器检测图像边缘 小结系列链接 0. 前言 Python 已逐渐成为数据分析/处理领域中的主要语言&#xff0c;这得益于 Python 丰富的第三方库&#xf…

【对顶队列】【中位数贪心】【前缀和】100227. 拾起 K 个 1 需要的最少行动次数

本文涉及知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 对顶队列&#xff08;栈&#xff09; 分类讨论 LeetCode100227. 拾起 K 个 1 需要的最少行动次数 给你一个下标从 0 开始的二进制数组 nums&#xff0c;其长度为 n &#x…