当前位置: 首页 > news >正文

UVM环境中reset复位的处理

文章目录

  • 前言
  • 一、单独处理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 interface
  reset_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: new

  virtual 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) begin
      sqr = reset_sequencer::type_id::create("sqr", this);
      drv = reset_driver::type_id::create("drv", this);
    end
    mon = reset_monitor::type_id::create("mon", this);
  endfunction: build_phase

  virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    if (is_active == UVM_ACTIVE) begin
      drv.seq_item_port.connect(sqr.seq_item_export);
    end
  endfunction: connect_phase

  virtual 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");
    end
  endfunction: end_of_elaboration_phase

endclass

/*
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_end

  function 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: new

  virtual 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_phase

  virtual 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");
    end
  endfunction: end_of_elaboration_phase

  virtual task run_phase(uvm_phase phase);
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);

    forever begin
      seq_item_port.get_next_item(req);
      drive(req);
      seq_item_port.item_done();
    end
  endtask: run_phase

  virtual task drive(reset_tr tr);
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    if (tr.kind == reset_tr::ASSERT) begin
      vif.reset_n = 1'b0;
      repeat(tr.cycles) @(vif.mst);
    end else begin
      vif.reset_n <= '1;
      repeat(tr.cycles) @(vif.mst);
    end
  endtask: drive
endclass

class reset_monitor extends uvm_monitor;
  virtual reset_io vif;          // DUT virtual interface
  uvm_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: new

  virtual 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_phase

  virtual 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");
    end
  endfunction: end_of_elaboration_phase

  virtual task run_phase(uvm_phase phase);
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);

    forever begin
      reset_tr tr = reset_tr::type_id::create("tr", this);
      detect(tr);
      analysis_port.write(tr);//此处可以空置,不连没关系
    end
  endtask: run_phase

  virtual 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) begin
      tr.kind = reset_tr::ASSERT;
      reset_event.trigger();
    end else begin
      tr.kind = reset_tr::DEASSERT;
      reset_event.reset();
    end
  endtask: 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_end

  function 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__SV

interface reset_io(input logic clk);
	logic        reset_n;

	clocking mst @(posedge clk);
		output reset_n;
	endclocking

	clocking mon @(posedge clk);
		input reset_n;
	endclocking

	modport 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_env

function top_env_ral_env::new(string name= "top_env_ral_env",uvm_component parent=null);
   super.new(name,parent);
endfunction:new

function 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_phase

function void top_env_ral_env::start_of_simulation_phase(uvm_phase phase);
   super.start_of_simulation_phase(phase);
   `ifdef UVM_VERSION_1_0
   uvm_top.print_topology();  
   factory.print();          
   `endif
   
   `ifdef UVM_VERSION_1_1
	uvm_root::get().print_topology(); 
    uvm_factory::get().print();      
   `endif

   `ifdef UVM_POST_VERSION_1_1
	uvm_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_1
     set_automatic_phase_objection(1);
    `endif
  endfunction: new

  virtual 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;});
    `endif

  endtask: body

  `ifdef UVM_VERSION_1_1
  virtual task pre_start();
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    if ((get_parent_sequence() == null) && (starting_phase != null)) begin
      starting_phase.raise_objection(this);
    end
  endtask: pre_start

  virtual task post_start();
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    if ((get_parent_sequence() == null) && (starting_phase != null)) begin
      starting_phase.drop_objection(this);
    end
  endtask: post_start
  `endif

endclass: 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__SV

typedef 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);
  endfunction

  virtual 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_phase
    uvm_config_db #(uvm_object_wrapper)::set(this, "env.host_agt.sqr.main_phase",
                    "default_sequence", host_bfm_sequence::get_type()); //main_phase
  endfunction
  
endclass : 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-name
	
   initial begin
      uvm_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);//全局set
      run_test();
   end

endmodule: 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__SV

module top_env_top();

   logic clk;
   logic rst;

   // Clock Generation
   parameter sim_cycle = 10;
   
   // Reset Delay Parameter
   parameter rst_delay = 50;

   always 
      begin
         #(sim_cycle/2) clk = ~clk;
      end
      
   host_io   host_if(clk);
   reset_io  reset_if(clk);
      
   top_env_tb_mod test(); // 1、例化testbench
   
   // ToDo: Include Dut instance here
  router    dut(.clk(clk), .reset_n(reset_if.reset_n), .io(router_if), .host(host_if));  // 2、例化DUT
      
   //Driver reset depending on rst_delay
   initial
      begin
         clk = 0;  //这一条必须要,不然时钟没有初始值,仿真会挂死
      //  rst = 1;
      //#1 rst = 0;
      //   repeat (rst_delay) @(clk);
      //   rst = 1'b1;
      //   @(clk);
   end

    initial begin
	    $fsdbDumpfile("novas.fsdb");
	    $fsdbDumpvars("+all");
	    $fsdbDumpMDA(0, top_env_top);
    end
    
endmodule: 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_1
     set_automatic_phase_objection(1);
    `endif
  endfunction: new

  virtual 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_VERSION
        begin
          reset_event.wait_on();
          `uvm_do_on(h_seq, p_sequencer.h_sqr);
        end
      // For IEEE UVM
      `else
        begin
          reset_event.wait_on();
          `uvm_do(h_seq, p_sequencer.h_sqr);
        end
      `endif
    join

  endtask: body

  `ifdef UVM_VERSION_1_1
  virtual task pre_start();
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    if ((get_parent_sequence() == null) && (starting_phase != null)) begin
      starting_phase.raise_objection(this);
    end
  endtask: pre_start

  virtual task post_start();
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    if ((get_parent_sequence() == null) && (starting_phase != null)) begin
      starting_phase.drop_objection(this);
    end
  endtask: post_start
  `endif

endclass: 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__SV

typedef 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);
  endfunction

  virtual 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());
  endfunction
  
    virtual 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_1
     set_automatic_phase_objection(1);
    `endif
  endfunction: new

  virtual task pre_start();
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    p_sqr = get_sequencer();// 2、通过获取句柄来例化

    `ifdef UVM_VERSION_1_1
    if ((get_parent_sequence() == null) && (starting_phase != null)) begin
      starting_phase.raise_objection(this);
    end
    `endif

    if (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);
    end
    else
	    `uvm_fatal("HOST_SEQ_CFG", "Has not access to host interface")
  endtask: pre_start

  `ifdef UVM_VERSION_1_1
  virtual task post_start();
    `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
    if ((get_parent_sequence() == null) && (starting_phase != null)) begin
      starting_phase.drop_objection(this);
    end
  endtask: post_start
  `endif

endclass: host_sequence_base


class 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: new

  virtual 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

相关文章:

  • 示波器探头的选择和作用及原理
  • 新学期,我的FLAG不能倒~
  • 好心情精神心理科医生:精神病人为何会出现幻觉?
  • java计算机毕业设计ssm电子元件仓库管理系统
  • 数据结构与算法--数组
  • jvm oom内存溢出,导出dump,使用mat进行问题分析
  • 百钱百鸡问题(C++枚举法)
  • 基于SSM实现智慧幼儿园信息管理系统
  • 九月组队学习计划!
  • OJ在线编程输入输出(Java版)
  • Matlab代码批处理中国地面气象日值数据集(2400站点数据集),提取所需省份全部站点数据
  • 链表之头指针、头结点、首元结点、空链表
  • 【Linux】静态库与共享库
  • POI入门
  • 07- 诊断事件diagnostic events的类图关系
  • css系列之关于字体的事
  • Django 博客开发教程 16 - 统计文章阅读量
  • Git同步原始仓库到Fork仓库中
  • js学习笔记
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • oldjun 检测网站的经验
  • PhantomJS 安装
  • php的插入排序,通过双层for循环
  • Spring Boot MyBatis配置多种数据库
  • swift基础之_对象 实例方法 对象方法。
  • Web Storage相关
  • 阿里研究院入选中国企业智库系统影响力榜
  • 搞机器学习要哪些技能
  • 关于springcloud Gateway中的限流
  • 前端存储 - localStorage
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 使用SAX解析XML
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 我与Jetbrains的这些年
  • 消息队列系列二(IOT中消息队列的应用)
  • 正则表达式-基础知识Review
  • ​MySQL主从复制一致性检测
  • ​低代码平台的核心价值与优势
  • #AngularJS#$sce.trustAsResourceUrl
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • (k8s中)docker netty OOM问题记录
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (WSI分类)WSI分类文献小综述 2024
  • (补)B+树一些思想
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (十) 初识 Docker file
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (原)本想说脏话,奈何已放下
  • (原創) 如何刪除Windows Live Writer留在本機的文章? (Web) (Windows Live Writer)
  • (转)LINQ之路
  • (转)大型网站的系统架构
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .NET 使用配置文件
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池