文章目录

  • 前言
  • 一、单独处理reset复位信号
    • 1.1 复位agent的实现
    • 1.2 复位transaction和interface
    • 1.3 environment
    • 1.4 复位sequence
    • 1.5 Top_env_test
    • 1.6 Top_env_tb
    • 1.7 Top_env_top
    • 1.8 小结
  • 二、处理其他驱动接口的复位值
    • 2.1 顶层管理复位的sqr和seq
    • 2.2 base_test
    • 2.3 host_reset_sequence
    • 2.4 小结
  • 总结

前言

复位存在于每一个验证环境中,简单的同时,也是我们最容易忽略的功能点。在验证环境中,通常复位信号的处理,就是在top顶层产生时钟时,做一个复位的动作。这样做的好处是简单,但是如果我们想在仿真过程中,加入一个复位的动作,实现起来就比较麻烦,对于接口上,复位后驱动的复位值,也难以实现。
本文主要介绍一种通用的方法,专门用来处理复位,具备很好的移植性,复用性,使用起来也非常方便,将复位相关的内容,单独拿出来处理,能够解决常规验证环境中,无法中间加入复位动作的痛点。
本文的思路是,先将复位信号单独拿出来进行处理,再介绍如何处理其他驱动接口上的复位值。


一、单独处理reset复位信号

单独处理reset复位信号的思路是,为复位信号单独建立一个agent,再建立复位信号的sequence,通过将复位信号的sequence,送入复位agent下sequencer中的reset_phase,其他驱动接口的sequence送入main_phase,从而实现系统仿真前的复位。

1.1 复位agent的实现

复位agent中包括driver、monitor、sequencer。这部分代码可以直接复用。

reset_agent.sv

typedef class reset_driver;
typedef class reset_monitor;class reset_agent extends uvm_agent;typedef uvm_sequencer#(reset_tr) reset_sequencer;virtual reset_io vif;          // DUT virtual interfacereset_sequencer  sqr;reset_driver     drv;reset_monitor    mon;`uvm_component_utils(reset_agent)function new(string name, uvm_component parent);super.new(name, parent);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);endfunction: newvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);`uvm_info("RSTCFG", $sformatf("Reset agent %s setting for is_active is: %p", this.get_name(), is_active), UVM_MEDIUM);uvm_config_db#(virtual reset_io)::get(this, "", "reset_if", vif);uvm_config_db#(virtual reset_io)::set(this, "*", "vif", vif);if (is_active == UVM_ACTIVE) beginsqr = reset_sequencer::type_id::create("sqr", this);drv = reset_driver::type_id::create("drv", this);endmon = reset_monitor::type_id::create("mon", this);endfunction: build_phasevirtual function void connect_phase(uvm_phase phase);super.connect_phase(phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if (is_active == UVM_ACTIVE) begindrv.seq_item_port.connect(sqr.seq_item_export);endendfunction: connect_phasevirtual function void end_of_elaboration_phase(uvm_phase phase);super.end_of_elaboration_phase(phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if (vif == null) begin`uvm_fatal("CFGERR", "Interface for reset agent not set");endendfunction: end_of_elaboration_phaseendclass/*
class reset_tr extends uvm_sequence_item;typedef enum {ASSERT, DEASSERT} kind_e;rand kind_e kind;rand int unsigned cycles = 1;`uvm_object_utils_begin(reset_tr)`uvm_field_enum(kind_e, kind, UVM_ALL_ON)`uvm_field_int(cycles, UVM_ALL_ON)`uvm_object_utils_endfunction new(string name = "reset_tr");super.new(name);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);endfunction: new
endclass
*/class reset_driver extends uvm_driver #(reset_tr);virtual reset_io vif;          // DUT virtual interface`uvm_component_utils(reset_driver)function new(string name, uvm_component parent);super.new(name, parent);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);endfunction: newvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);uvm_config_db#(virtual reset_io)::get(this, "", "vif", vif);endfunction: build_phasevirtual function void end_of_elaboration_phase(uvm_phase phase);super.end_of_elaboration_phase(phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if (vif == null) begin`uvm_fatal("CFGERR", "Interface for reset driver not set");endendfunction: end_of_elaboration_phasevirtual task run_phase(uvm_phase phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);forever beginseq_item_port.get_next_item(req);drive(req);seq_item_port.item_done();endendtask: run_phasevirtual task drive(reset_tr tr);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if (tr.kind == reset_tr::ASSERT) beginvif.reset_n = 1'b0;repeat(tr.cycles) @(vif.mst);end else beginvif.reset_n <= '1;repeat(tr.cycles) @(vif.mst);endendtask: drive
endclassclass reset_monitor extends uvm_monitor;virtual reset_io vif;          // DUT virtual interfaceuvm_analysis_port #(reset_tr) analysis_port;uvm_event reset_event = uvm_event_pool::get_global("reset");`uvm_component_utils(reset_monitor)function new(string name, uvm_component parent);super.new(name, parent);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);endfunction: newvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);uvm_config_db#(virtual reset_io)::get(this, "", "vif", vif);analysis_port = new("analysis_port", this);endfunction: build_phasevirtual function void end_of_elaboration_phase(uvm_phase phase);super.end_of_elaboration_phase(phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if (vif == null) begin`uvm_fatal("CFGERR", "Interface for reset monitor not set");endendfunction: end_of_elaboration_phasevirtual task run_phase(uvm_phase phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);forever beginreset_tr tr = reset_tr::type_id::create("tr", this);detect(tr);analysis_port.write(tr);//此处可以空置,不连没关系endendtask: run_phasevirtual task detect(reset_tr tr);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);@(vif.reset_n);assert(!$isunknown(vif.reset_n));if (vif.reset_n == 1'b0) begintr.kind = reset_tr::ASSERT;reset_event.trigger();end else begintr.kind = reset_tr::DEASSERT;reset_event.reset();endendtask: detect
endclass

1.2 复位transaction和interface

这部分代码拿过来复用就好了。

reset_tr.sv

class reset_tr extends uvm_sequence_item;typedef enum {ASSERT, DEASSERT} kind_e;rand kind_e kind;rand int unsigned cycles = 1;`uvm_object_utils_begin(reset_tr)`uvm_field_enum(kind_e, kind, UVM_ALL_ON)`uvm_field_int(cycles, UVM_ALL_ON)`uvm_object_utils_endfunction new(string name = "reset_tr");super.new(name);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);endfunction: new
endclass

reset_io.sv

`ifndef RESET_IO__SV
`define RESET_IO__SVinterface reset_io(input logic clk);logic        reset_n;clocking mst @(posedge clk);output reset_n;endclockingclocking mon @(posedge clk);input reset_n;endclockingmodport dut(input reset_n);
endinterface: reset_io
`endif

1.3 environment

在env中声明和例化1.2节中的复位agent。host_agent用于配置寄存器,这里env只展示了部分代码。

top_env_ral_env.sv

`ifndef TOP_ENV_RAL_ENV__SV
`define TOP_ENV_RAL_ENV__SV
`include "top_env.sv"
class top_env_ral_env extends uvm_env;host_agent host_agt;reset_agent reset_agt;//1、申明`uvm_component_utils(top_env_ral_env)extern function new(string name="top_env_ral_env", uvm_component parent=null);extern virtual function void build_phase(uvm_phase phase);extern function void start_of_simulation_phase(uvm_phase phase);
endclass: top_env_ral_envfunction top_env_ral_env::new(string name= "top_env_ral_env",uvm_component parent=null);super.new(name,parent);
endfunction:newfunction void top_env_ral_env::build_phase(uvm_phase phase);super.build_phase(phase);host_agt = host_agent::type_id::create("host_agt",this);reset_agt = reset_agent::type_id::create("reset_agt",this); //2、例化
endfunction: build_phasefunction void top_env_ral_env::start_of_simulation_phase(uvm_phase phase);super.start_of_simulation_phase(phase);`ifdef UVM_VERSION_1_0uvm_top.print_topology();  factory.print();          `endif`ifdef UVM_VERSION_1_1uvm_root::get().print_topology(); uvm_factory::get().print();      `endif`ifdef UVM_POST_VERSION_1_1uvm_root::get().print_topology(); uvm_factory::get().print();      `endif//ToDo : Implement this phase here
endfunction: start_of_simulation_phase`endif // TOP_ENV_RAL_ENV__SV

1.4 复位sequence

编写复位的sequence,用于控制复位信号。这部分代码可以直接拿来复用。

reset_sequence.sv

class reset_sequence extends uvm_sequence #(reset_tr);`uvm_object_utils(reset_sequence)function new(string name = "reset_sequence");super.new(name);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);`ifndef UVM_VERSION_1_1set_automatic_phase_objection(1);`endifendfunction: newvirtual task body();`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);// For UVM-1.1 & UVM-1.2//`ifndef UVM_VERSION`uvm_do_with(req, {kind == DEASSERT; cycles == 2;});`uvm_do_with(req, {kind == ASSERT; cycles == 1;});`uvm_do_with(req, {kind == DEASSERT; cycles == 15;});//// For IEEE UVM//`else`uvm_do(req,,, {kind == DEASSERT; cycles == 2;});`uvm_do(req,,, {kind == ASSERT; cycles == 1;});`uvm_do(req,,, {kind == DEASSERT; cycles == 15;});`endifendtask: body`ifdef UVM_VERSION_1_1virtual task pre_start();`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if ((get_parent_sequence() == null) && (starting_phase != null)) beginstarting_phase.raise_objection(this);endendtask: pre_startvirtual task post_start();`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if ((get_parent_sequence() == null) && (starting_phase != null)) beginstarting_phase.drop_objection(this);endendtask: post_start`endifendclass: reset_sequence

1.5 Top_env_test

在base_test中,将复位的sequence,送入复位agent下sequencer的reset_phase中,而配置寄存器的host_bfm_sequence则送入的是main_phase中,通过UVM phase的执行顺序,来保证复位在前,配置寄存器在后。

`ifndef TEST__SV
`define TEST__SVtypedef class top_env_ral_env;class base_test extends uvm_test;`uvm_component_utils(base_test)top_env_ral_env env;function new(string name, uvm_component parent);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);env = top_env_ral_env::type_id::create("env", this);uvm_config_db #(uvm_object_wrapper)::set(this, "env.reset_agt.sqr.reset_phase", "default_sequence", reset_sequence::get_type());//reset_phaseuvm_config_db #(uvm_object_wrapper)::set(this, "env.host_agt.sqr.main_phase","default_sequence", host_bfm_sequence::get_type()); //main_phaseendfunctionendclass : base_test`endif //TEST__SV

1.6 Top_env_tb

在tb中,将top层的interface传递到env中。

`ifndef TOP_ENV_TB_MOD__SV
`define TOP_ENV_TB_MOD__SV`include "mstr_slv_intfs.incl"
module top_env_tb_mod;import uvm_pkg::*;`include "top_env_ral_env.sv"
`include "top_env_test.sv"  //ToDo: Change this name to the testcase file-nameinitial beginuvm_config_db #(virtual host_io)::set(null,"","host_if",top_env_top.host_if);uvm_config_db #(virtual reset_io)::set(null,"","reset_if",top_env_top.reset_if);//全局setrun_test();endendmodule: top_env_tb_mod`endif // TOP_ENV_TB_MOD__SV

1.7 Top_env_top

在top层,分别例化tb和DUT。

`ifndef TOP_ENV_TOP__SV
`define TOP_ENV_TOP__SVmodule top_env_top();logic clk;logic rst;// Clock Generationparameter sim_cycle = 10;// Reset Delay Parameterparameter rst_delay = 50;always begin#(sim_cycle/2) clk = ~clk;endhost_io   host_if(clk);reset_io  reset_if(clk);top_env_tb_mod test(); // 1、例化testbench// ToDo: Include Dut instance hererouter    dut(.clk(clk), .reset_n(reset_if.reset_n), .io(router_if), .host(host_if));  // 2、例化DUT//Driver reset depending on rst_delayinitialbeginclk = 0;  //这一条必须要,不然时钟没有初始值,仿真会挂死//  rst = 1;//#1 rst = 0;//   repeat (rst_delay) @(clk);//   rst = 1'b1;//   @(clk);endinitial begin$fsdbDumpfile("novas.fsdb");$fsdbDumpvars("+all");$fsdbDumpMDA(0, top_env_top);endendmodule: top_env_top`endif // TOP_ENV_TOP__SV

1.8 小结

到此为止,展示了一个完整的,通过sequence去控制复位信号的处理方法,这其中大部分代码,可以直接在不同的环境中复用。

二、处理其他驱动接口的复位值

第一章中演示了复位信号的处理方法,除了复位信号,环境中还有许多其他的信号,在系统处于复位的时候,需要特定的驱动值。
最简单的一个思路就是,为这些驱动信号,单独创建一个复位值的sequence,然后将这个sequence送入对应agent的reset_phase中。
这样做会存在一些问题,由于不同的组件的reset_phase之间,没有严格的执行先后的顺序,会出现驱动信号的复位sequence先执行,造成在仿真的0时刻,在还没有复位信号的情况下,0时刻输入到DUT的信号处于已知值。

处理外部信号的正确方法是让信号在0时刻默认为它们的默认状态(x表示逻辑,z表示连线)。然后,在testbench中,当检测到复位信号时,将这些信号设置为适当的复位值。

解决方法是加入一个顶层的复位的sqr和seq。

2.1 顶层管理复位的sqr和seq

在顶层管理的sqr中,声明两个sqr,一个reset_sequencer,另一个host_sequencer。
top_reset_sequencer.sv

typedef class host_data;
class top_reset_sequencer extends uvm_sequencer;`uvm_component_utils(top_reset_sequencer)typedef uvm_sequencer#(reset_tr) reset_sequencer;typedef uvm_sequencer#(host_data) host_sequencer;reset_sequencer  r_sqr;host_sequencer h_sqr;function new(string name, uvm_component parent);super.new(name, parent);    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);endfunction: new
endclass: top_reset_sequencer

顶层管理的seq中的信息含量比较大,通过以下几点来分解:
1、举手和放手通用性处理。对于高于UVM1.1版本,则通过在new函数中,通过set_automatic_phase_objection(1)来实现,对于UVM1.1版本,则在pre_start和post_start中进行举手和放手。这部分代码适用任何sequence。
2、p_sequencer的应用。由于调用了`uvm_declare_p_sequencer(top_reset_sequencer)这个宏,所以所有的seq,都可以通过p_sequencer来下发。
3、reset_event的使用。由于在body任务中,seq通过fork–join的方式并行下发,为了控制复位信号先执行,驱动信号后执行,这里通过利用了一个全局复位的事件reset_event,这个复位事件在复位agent下的monitor中进行触发,从而保证先给复位信号,再给驱动信号。

top_reset_sequence.sv

typedef  class host_reset_sequence ;
class top_reset_sequence extends uvm_sequence;`uvm_object_utils(top_reset_sequence)`uvm_declare_p_sequencer(top_reset_sequencer)uvm_event reset_event = uvm_event_pool::get_global("reset");reset_sequence                    r_seq;host_reset_sequence    h_seq;function new(string name="virtual_reset_sequence");super.new(name);    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);`ifndef UVM_VERSION_1_1set_automatic_phase_objection(1);`endifendfunction: newvirtual task body();`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);fork// For UVM-1.1 & UVM-1.2`ifndef UVM_VERSION`uvm_do_on(r_seq, p_sequencer.r_sqr);// For IEEE UVM`else`uvm_do(r_seq, p_sequencer.r_sqr);`endif// For UVM-1.1 & UVM-1.2`ifndef UVM_VERSIONbeginreset_event.wait_on();`uvm_do_on(h_seq, p_sequencer.h_sqr);end// For IEEE UVM`elsebeginreset_event.wait_on();`uvm_do(h_seq, p_sequencer.h_sqr);end`endifjoinendtask: body`ifdef UVM_VERSION_1_1virtual task pre_start();`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if ((get_parent_sequence() == null) && (starting_phase != null)) beginstarting_phase.raise_objection(this);endendtask: pre_startvirtual task post_start();`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if ((get_parent_sequence() == null) && (starting_phase != null)) beginstarting_phase.drop_objection(this);endendtask: post_start`endifendclass: top_reset_sequence

2.2 base_test

增加的top_reset_sequencer被声明例化在base_test中,同时在connect_phase中,要将其与底层的sqr连接起来。另外,原有组件中reset_phase需要被清空,再将top_reset_sequence送入到top_reset_sqr.reset_phase。
这样做的另外一个好处是,如果顶层需要在仿真过程中,加入一个复位的过程,那么只需要将其他main_phase清空后,再将top_reset_sequence送入top_reset_sqr.main_phase中。

top_env_test.sv

`ifndef TEST__SV
`define TEST__SVtypedef class top_env_ral_env;
class base_test extends uvm_test;`uvm_component_utils(base_test)top_env_ral_env env;top_reset_sequencer top_reset_sqr;// 1、声明function new(string name, uvm_component parent);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);env = top_env_ral_env::type_id::create("env", this);top_reset_sqr = top_reset_sequencer::type_id::create("top_reset_sqr", this);//2、例化uvm_config_db #(uvm_object_wrapper)::set(this, "env.host_agt.sqr.main_phase","default_sequence", host_bfm_sequence::get_type()); uvm_config_db #(uvm_object_wrapper)::set(this, "env.*.sqr.reset_phase", "default_sequence", null);uvm_config_db #(uvm_object_wrapper)::set(this, "top_reset_sqr.reset_phase", "default_sequence", top_reset_sequence::get_type());endfunctionvirtual function void connect_phase(uvm_phase phase);super.connect_phase(phase);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);top_reset_sqr.r_sqr = env.reset_agt.sqr;//3、连接top_reset_sqr.h_sqr = env.host_agt.sqr;endfunction: connect_phase
endclass : base_test
`endif //TEST__SV

2.3 host_reset_sequence

这里再介绍一下,top_reset_sequence中host_reset_sequence的实现。实现的主要思路是,通过uvm_config_db去get到host的interface,然后在task body中直接对其进行赋值。
具体的是现实:
1、声明p_sqr。
2、例化。在pre_start中,通过get_sequencer来获取句柄实现例化。
3、获取host的interface。借助p_sqr.get_parent()来获取路径,从而得到interface的句柄,进而可以对其进行赋值。

host_reset_sequence.sv

class host_sequence_base extends uvm_sequence #(host_data);`uvm_object_utils(host_sequence_base)virtual host_io    vif;uvm_sequencer_base p_sqr;// 1、声明function new(string name = "host_sequence_base");super.new(name);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);`ifndef UVM_VERSION_1_1set_automatic_phase_objection(1);`endifendfunction: newvirtual task pre_start();`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);p_sqr = get_sequencer();// 2、通过获取句柄来例化`ifdef UVM_VERSION_1_1if ((get_parent_sequence() == null) && (starting_phase != null)) beginstarting_phase.raise_objection(this);end`endifif (uvm_config_db#(virtual host_io)::get(p_sqr.get_parent(), "", "host_if", vif)) begin// 3、获取host的interface`uvm_info("HOST_SEQ_CFG", "Has access to host interface", UVM_HIGH);endelse`uvm_fatal("HOST_SEQ_CFG", "Has not access to host interface")endtask: pre_start`ifdef UVM_VERSION_1_1virtual task post_start();`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);if ((get_parent_sequence() == null) && (starting_phase != null)) beginstarting_phase.drop_objection(this);endendtask: post_start`endifendclass: host_sequence_baseclass host_reset_sequence extends host_sequence_base;`uvm_object_utils(host_reset_sequence)function new(string name = "host_reset_sequence");super.new(name);`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);endfunction: newvirtual task body();vif.wr_n = 1'b1;vif.rd_n = 1'b1;vif.address ='z;vif.data = 'z;endtask: body
endclass: host_reset_sequence

2.4 小结

这里提供了一种处理驱动信号复位值的方法,类似的方法可以用在其他多组驱动接口上。


总结

本文主要介绍了一种复位信号,以及驱动信号复位值的处理方法,虽然增加了验证组件,实现起来较为复杂,但是能够解决常规方法,无法在仿真过程中加入复位的痛点,具备很好的灵活性,实现的代码具备高度的复用性和可移植性。

附上工程代码链接
https://download.csdn.net/download/hh199203/86512045

UVM环境中reset复位的处理相关推荐

  1. 【UVM理论】uvm环境中对uvm_config_db的理解

    如有错误或疑问,欢迎留言,我将尽力回答!共同学习,共同进步! 一.uvm_config_db的用途大概有如下三种: *(1) 传递virtual interface到环境中:**(2) 设置单一变量值 ...

  2. [UVM]UVM环境中的clock agent方案

    UVM环境中的clock agent方案 摘要:在验证环境中,我们通常需要多个不同频率的时钟,为了能方便的产生所需时钟,我们可以开发一个clk_agent,通过config来指定频率,通过interf ...

  3. uvm环境中收集coverage的方法

    收集coverage主要有两块,一个是reg类型的coverage,另一个是功能性的coverage. 针对reg类型,使用ralgen生成的reg model可以自动收集coverage. 1.用i ...

  4. FPGA开发中全局复位置位(GSR)

    最近几天读了Xilinx网站上一个很有意思的白皮书(white paper,wp272.pdf),名字叫<Get Smart About Reset:Think Local, Not Globa ...

  5. FPGA开发中全局复位置位(GSR)简介

      最近几天读了Xilinx网站上一个很有意思的白皮书(white paper,wp272.pdf),名字叫<Get Smart About Reset:Think Local, Not Glo ...

  6. 验证环境中的program为什么必须是automatic

    最近在项目中,发现验证环境中的顶层的program(一般将program作为验证环境的入口),都是automatic的. 其实Program默认是static的,那么为什么需要把验证环境做成autom ...

  7. Ambari在离线环境中安装Hadoop集群

    2019独角兽企业重金招聘Python工程师标准>>> http://www.hackbase.com/article-973-1.html (WJW)Ambari在离线环境中安装H ...

  8. 在多任务(RTOS)环境中使用看门狗

    最近在SEGGER的博客上看到一篇有关在实时操作系统使用看门狗的文章.从一个失败的太空项目出发,分析了看门狗的作用及使用,自我感觉很有启发,特此翻译此文并推荐给各位同仁.为了阅读方便,有些航天领域名词 ...

  9. 阿里云环境中TLS/SSL握手失败的场景分析

    TLS/SSL握手是一个相对复杂的过程,在阿里云环境中结合产品,安全等特性,可能会让TLS/SSL握手过程的不定性更多.本文来总结下各种握手失败的场景. 一次TLS/SSL握手的过程 本文不详细介绍T ...

最新文章

  1. MIT出品2017-2018深度学习最新进展汇总
  2. MySQL完整备份,还原
  3. redis开启redis_Redis聚类
  4. format 参数说明
  5. Springboot2.x +JPA 集成 Apache ShardingSphere 读写分离
  6. php比较两个数组的键名统计有交集的数量,php比较两个数组的键名并返回交集的函数array_intersect_key()...
  7. c++ hsv 红色范围_维生素C的定量测定—2,6二氯酚靛酚法
  8. Oracle分页模板
  9. ubuntu18.04 下安装搜狗输入法
  10. TP5整合的阿里云短信接口
  11. 软件公司所犯的3种最严重的营销错误,你应该来看看
  12. flutter 报错 type ‘int‘ is not a subtype of type ‘String‘ 奇葩经历
  13. 第二人生的源码分析(十九)人物组合显示
  14. No module named libs.resources
  15. Python爬取哔哩哔哩视频
  16. echarts X轴文字竖向排列 ,一行两字竖向排列或旋转角度排列
  17. 四象限工作法:四象限时间管理法则及四象限工作法软件
  18. 解析微分电路和积分电路的区别
  19. 相位相关法计算图像位移
  20. 计算机计算器logo,电脑计算器在哪打开

热门文章

  1. 博客导流到微信公众号
  2. Kali安装教程及使用
  3. 特斯拉是不是蔚来的盟友?
  4. Linux C语言技术(5)-数组和字符串
  5. 普华永道、IBM、麦肯锡、埃森哲 (转)
  6. 顾问成长(13)-从麦肯锡30秒理论看顾问演讲时间控制
  7. MATLAB绘图自定义曲线颜色
  8. 常用Flask的插件bootstrap wtf
  9. 移动端分辨率和像素的基本知识
  10. QT-横向滚动显示字体