IC开发——Verilog简明教程

news2024/9/21 3:36:10

1. 基础概念

1.1. 逻辑值

  1. 逻辑0,低电平,对应电路中接地GND。

  1. 逻辑1,高电平,对应电路中的电源VCC。

  1. 逻辑Z,高阻态,对应电路的悬空。

  1. 逻辑X,未知态,数据仿真中可能存在,如2个信号同时驱动1个信号,异常状态。

1.2. 标识符

Verilog标识符可以使用字母、数字、下划线和$组合,且必须以字母或下划线开头,且大小写敏感。

  1. 模块名,模块名称应该简洁、描述性强,反映模块的功能,推荐驼峰命名法(CamelCase)。
  2. 端口名,端口名称应该简洁、描述性强,反映端口的功能,使用小写字母开头,采用蛇形命名法(snake_case)。
  3. 信号名称,信号名称应该简洁、描述性强,反映信号的功能,使用小写字母开头,采用蛇形命名法(snake_case)。
  4. 参数名称,使用全大写字母,采用下划线分隔的形式,如: DATA_WIDTH, ADDR_BITS, FIFO_DEPTH。
  5. 常量名称,全大写字母,采用下划线分隔的形式。

1.3. 数字进制

Verilog支持2进制、8进制、10进制和16进制。形式如下:

wire [7:0] data1 = 'b10101010; // 二进制
wire [7:0] data2 = 'o325;      // 八进制
wire [7:0] data3 = 123;        // 十进制
wire [7:0] data4 = 'hAB;       // 十六进制

1.4. 数据类型

  1. Wire (线网):
    • 用于连接模块之间的信号。
    • 声明方式: wire [<msb>:<lsb>] <signal_name>;
    • 例如: wire [7:0] data_bus;
  1. Reg (寄存器):
    • 用于存储和操作数据。
    • 声明方式: reg [<msb>:<lsb>] <signal_name>;
    • 例如: reg [3:0] counter;
  1. Integer (整数):
    • 用于表示有符号的整数,一般为32bit。
    • 声明方式: integer <variable_name>;
    • 例如: integer result;
  1. Real (浮点数):
    • 用于表示浮点数。
    • 声明方式: real <variable_name>;
    • 例如: real pi = 3.14;
  1. Time (时间):
    • 用于表示仿真时间。
    • 声明方式: time <variable_name>;
    • 例如: time start_time, end_time;
  1. Parameter (参数):
    • 用于定义常量。
    • 声明方式: parameter <parameter_name> = <value>;
    • 例如: parameter DATA_WIDTH = 8;
  1. Localparam (局部参数):
    • 用于定义模块内部的常量。
    • 声明方式: localparam <parameter_name> = <value>;
    • 例如: localparam BUFFER_SIZE = 1024;

1.5. 运算符

Verilog运算符和C类似,其优先级也和C相近,多用()显式优先级。

  1. 算术运算符:
    • +、-、*、/、%(取余)
  1. 位运算符:
    • &(按位与)、|(按位或)、^(按位异或)、~(按位取反)
    • <<(左移)、>>(右移)
  1. 逻辑运算符:
    • &&(逻辑与)、||(逻辑或)、!(逻辑非)
  1. 关系运算符:
    • <、>、<=、>=、==(等于)、!=(不等于)
  1. 条件运算符:
    • ?:(三目运算符)
  1. 位选择运算符:
    • [](选择位宽)
  1. 连接运算符:
    • {}(连接)
  1. 归约操作符
  • 归约操作符是一种特殊的操作符,用于对一个向量或位宽信号执行逻辑运算,并返回一个单个的布尔值结果。
  • 归约与操作符 (&)
  • 归约或操作符 (|)
  • 归约异或操作符 (^)
  • 归约 NAND 操作符 (~&)
  • 归约 NOR 操作符 (~|)
  • 归约 XNOR 操作符 (~^)

1.6. 注释

Verilog注释和C语言注释相同,一种是以“/*”符号开始,“*/”结束,另外一种以"//"开头。

1.7. 关键字

常见关键字如下:

  1. 基本关键字:
    • module、endmodule: 定义模块的开始和结束
    • input、output、inout: 定义模块的输入输出端口
    • wire、reg: 定义信号类型
    • always: 定义时序逻辑块
    • assign: 定义组合逻辑
  1. 数据类型关键字:
    • integer、real、time: 定义变量的数据类型
    • parameter、localparam: 定义参数
  1. 流程控制关键字:
    • if、else、case、default: 条件语句
    • for、while、repeat: 循环语句
    • begin、end: 语句块定界
  1. 时间延迟关键字:
    • #: 定义延迟时间
    • @: 定义事件触发
  1. 其他关键字:
    • initial: 定义初始化块
    • task、function: 定义任务和函数
    • specify、specparam: 定义时序约束
    • include: 包含外部文件
    • macromodule: 定义宏模块

2. 模块

2.1. 概念

模块(module)是 Verilog 的基本设计单位,是用于描述某个设计的功能或结构及与其他模块通信的外部端口。

模块在概念上可等同一个器件,就如调用通用器件(与门、三态门等)或通用宏单元(计数器、ALU、CPU)等。整个IC设计 是由多个模块嵌套构成。

模块有五个主要部分:端口定义、参数定义(可选)、 I/O 说明、内部信号声明、功能定义。模块总是以关键词 module 开始,以关键词 endmodule 结尾。

2.2. 构成

  1. 端口定义:
    • 使用 input、output、inout 关键字定义模块的输入、输出和双向端口。
    • 端口可以是线网类型(wire)或寄存器类型(reg)。
    • 端口宽度可以是单位宽度,也可以是总线宽度。
  1. 参数定义(可选):
    • 使用 parameter 或 localparam 关键字定义模块级参数。
    • 参数可以是常量表达式,在模块实例化时进行传递。
  1. I/O 说明:
    • 描述各个端口的功能和用途。
    • 有助于模块的理解和使用。
  1. 内部信号声明:
    • 使用 wire 或 reg 关键字声明模块内部的信号。
    • 这些信号用于连接模块内部的逻辑电路。
  1. 功能定义:
    • 使用 assign 语句定义组合逻辑电路。
    • 使用 always 语句块定义时序逻辑电路。
    • 可以包含参数、任务和函数等其他 Verilog 语法元素。

2.4. 模块例化

调用指定模块是通过模块例化实现的。

  1. 基本语法
module_instance_name instance_name (
  .port1(signal1),
  .port2(signal2),
  ...,
  .portN(signalN)
);
  1. 参数例化

模块的参数可以指定,也可以使用默认的。

module_name #(
  .param1(value1),
  .param2(value2),
  ...,
  .paramN(valueN)
) instance_name (
  .port1(signal1),
  .port2(signal2),
  ...,
  .portN(signalN)
);

2.3. 示例

// 模块定义
module EightMultiplier (
  // 输入输出端口定义
  input  [7:0] a,     // 8位输入操作数a
  input  [7:0] b,     // 8位输入操作数b
  output [15:0] prod  // 16位输出乘积
);

  // 参数定义(可选)
  parameter DELAY = 5; // 乘法器内部延迟时间

  // 内部信号声明
  reg [15:0] temp;

  // 功能定义
  always @(*) begin
    #DELAY; // 模拟内部延迟
    temp = a * b; // 8位乘法运算
  end

  // 输出赋值
  assign prod = temp;

endmodule

// 顶层模块定义
module TopModule (
  input  [7:0] a,
  input  [7:0] b,
  output [15:0] product
);

  // 例化 8bit_multiplier 模块
  EightMultiplier u_multiplier (
    .a(a),
    .b(b),
    .prod(product)
  );

endmodule

3. 函数

3.1. 概念

在 Verilog 中,函数是一种重要的功能模块,可以帮助我们封装一些常用的操作,提高代码的可重用性和可读性。

语法形式:

function [return_type] function_name;
  input [input_type] input_port1, input_port2, ..., input_portN;
  output [output_type] output_port1, output_port2, ..., output_portM;
  reg [internal_type] internal_variable1, internal_variable2, ..., internal_variableK;
  begin
    // 函数体
    function_body;
    // 返回值
    return return_value;
  end
endfunction

3.2. 示例

加法函数:

function [31:0] add_32bit;
  input [31:0] a, b;
  begin
    add_32bit = a + b;
  end
endfunction

4. 语法

4.1. 阻塞和非阻塞赋值

  1. 阻塞赋值 (
    • 阻塞赋值会立即执行,并阻塞当前过程的执行,直到赋值完成。
    • 在一个过程中,阻塞赋值语句的执行顺序与它们在代码中的顺序一致。
    • 阻塞赋值通常用于组合逻辑电路的描述。

示例:

always @(a, b) begin
  c = a + b;
  d = c * 2;
end

在这个例子中,c 的值会先被计算并赋值,然后 d 的值才会被计算并赋值。

  1. 非阻塞赋值 (
    • 非阻塞赋值会将右侧表达式的值暂存,并在当前过程结束时一次性更新左侧变量的值。
    • 在一个过程中,非阻塞赋值语句的执行顺序与它们在代码中的顺序无关,而是在过程结束时一次性更新。
    • 非阻塞赋值通常用于时序逻辑电路的描述。

示例:

always @(posedge clk) begin
  c <= a + b;
  d <= c * 2;
end

在这个例子中,c 和 d 的值会在时钟上升沿时一次性更新,而不是按照代码中的顺序执行。

4.2. 组合逻辑电路和时序逻辑电路

组合逻辑电路和时序逻辑电路是两种基本的数字电路类型,它们在结构和行为上有明显的区别:

  1. 组合逻辑电路:
    • 组合逻辑电路的输出仅取决于当前的输入,不依赖于任何历史状态或时序信号。
    • 组合逻辑电路没有存储元件,如寄存器或触发器,只有逻辑门电路。
    • 组合逻辑电路的输出会立即响应输入的变化,没有延迟。
    • 组合逻辑电路通常用于实现简单的逻辑功能,如加法器、译码器等。
    • 在 Verilog 中,组合逻辑电路通常使用阻塞赋值 (=) 描述。
  1. 时序逻辑电路:
    • 时序逻辑电路的输出不仅取决于当前的输入,还依赖于电路的历史状态。
    • 时序逻辑电路包含存储元件,如寄存器或触发器,用于存储和保持状态信息。
    • 时序逻辑电路的输出会根据时钟信号的变化而更新,存在一定的延迟。
    • 时序逻辑电路通常用于实现复杂的状态机、计数器、移位寄存器等功能。
    • 在 Verilog 中,时序逻辑电路通常使用非阻塞赋值 (<=) 描述。

组合逻辑电路和时序逻辑电路的设计和分析方法也有所不同:

  • 组合逻辑电路的设计通常基于布尔代数和逻辑门电路,可以使用卡诺图、Quine-McCluskey 算法等方法进行化简和优化。
  • 时序逻辑电路的设计需要考虑时钟信号、状态转移图、状态编码等因素,通常需要使用状态机分析和设计方法。

4.3. always语句

Verilog 中的 always 语句是用于描述电路行为的重要语句,它可以用来描述组合逻辑电路和时序逻辑电路。always 语句的基本语法如下:

always @(sensitivity_list)
  statement;

其中:

  1. sensitivity_list 是一个由信号名组成的列表,用于指定 always 语句的敏感性。当列表中的任何一个信号发生变化时,always 语句中的语句就会被执行。
  2. statement 是一个或多个 Verilog 语句,用于描述电路的行为。这些语句可以是赋值语句、条件语句、循环语句等。

always 语句的使用方式有两种:

  1. 组合逻辑电路描述:
    • sensitivity_list 包含所有相关的输入信号。
    • 使用阻塞赋值 (=) 描述输出信号的计算过程。
    • 输出信号会立即响应输入信号的变化。

例如:

always @(a, b, c)
  out = (a & b) | c;
  1. 时序逻辑电路描述:
    • sensitivity_list 包含时钟信号和可能的异步复位/置位信号。
    • 使用非阻塞赋值 (<=) 描述状态寄存器的更新过程。
    • 输出信号会根据时钟信号的变化而更新。

例如:

always @(posedge clk or negedge rst_n)
  if (~rst_n)
    q <= 1'b0;
else
  q <= d;

在实际的 Verilog 代码中,我们通常会结合使用多个 always 语句来描述复杂的数字电路。合理地使用 always 语句可以帮助我们更好地理解和设计数字电路的行为。

4.4. for语句

Verilog 中的 for 循环语句用于实现重复性的操作。它的基本语法如下:

for (initialize; condition; step)
  statement;

其中:

  1. initialize: 初始化语句,在循环开始前执行一次。通常用于设置循环计数器的初始值。
  2. condition: 循环条件,在每次循环开始前检查。只有当条件为真时,才会执行循环体。
  3. step: 循环计数器的更新语句,在每次循环结束后执行。通常用于增加或减少计数器的值。
  4. statement: 循环体,包含一个或多个 Verilog 语句。这些语句会在满足循环条件时重复执行。

下面是一个简单的例子,用 for 循环实现 8 位加法器:

module adder8(a, b, sum);
  input [7:0] a, b;
  output [7:0] sum;

  reg [7:0] sum;

  always @(a or b) begin
    sum = 0;
    for (int i = 0; i < 8; i = i + 1)
      sum[i] = a[i] ^ b[i] ^ sum[i];
  end
endmodule

在这个例子中:

  1. 循环初始化将 sum 寄存器清零。
  2. 循环条件 i < 8 确保循环执行 8 次,对应 8 位加法器的位宽。
  3. 循环步进 i = i + 1 会在每次循环结束后将计数器 i 增加 1。
  4. 循环体中的语句实现了单位位的异或运算,得到最终的 8 位加法结果。

4.5. generate语句

Verilog 中的 generate 语句用于在编译时动态生成 Verilog 代码。它可以用于创建重复性的电路结构,如数组、寄存器堆等。

generate 语句的基本语法如下:

generate
  if (condition) begin:block_name
    // code block
  end
  else begin:block_name
    // code block
  end
endgenerate

或者:

generate
    for (initialize; condition; step) begin:block_name
        // code block
    end
endgenerate

generate 语句中的代码块会在编译时展开,而不是在仿真时执行。这意味着 generate 语句中的代码不会被视为普通的 Verilog 语句,而是用于生成新的 Verilog 代码。

generate语句后的代码不能真实对应真实的电路,需要编译展开来对应真实的电路。展开的过程中,通过block_name来标识展开的代码。

4.6. task语句

在 Verilog 中,task 是一种特殊的语句块,用于定义可重复使用的代码段。它类似于函数,但与函数不同的是,task 可以包含任意数量的语句,并且可以修改外部变量的值。

task 的基本语法如下:

task task_name;
  // 任务内部的声明和语句
  begin
    // 任务内部的代码
  end
endtask

task 的使用方法如下:

task_name;

4.7. initial语句

在 Verilog 中,initial 语句是一种特殊的语句,用于在仿真开始时执行一次性的初始化操作。

initial 语句的基本语法如下:

initial 
  begin
    // 初始化代码块
  end

initial 语句的主要特点包括:

  1. 仅执行一次: initial 语句只会在仿真开始时执行一次,而不会在仿真过程中重复执行。
  2. 独立执行: initial 语句独立于 Verilog 模块的其他部分,不受时钟信号或其他事件的控制。
  3. 可包含任意语句: initial 语句可以包含任意数量的 Verilog 语句,如赋值语句、条件语句、循环语句等。
  4. 常用于初始化: initial 语句通常用于在仿真开始时初始化寄存器、内存、状态机等硬件元素的初始状态。

初始化寄存器或变量的值:

initial begin
  $display("Simulation started at %0t", $time);
  #100 $finish;
end

4.8. case 语句

case语句是Verilog中的一种选择结构,用于基于给定的表达式值进行多路选择。

module Example (
  input [1:0] sel,
  output reg out
);

  always @*
    begin
      case (sel)
        2'b00: out = 0;          // 当sel等于00时,out为0
        2'b01: out = 1;          // 当sel等于01时,out为1
        2'b10, 2'b11: out = 2;   // 当sel等于10或11时,out为2
        default: out = 0;        // 默认情况下,out为0
      endcase
    end

endmodule

在上述示例中,根据sel的值进行了多路选择。当sel等于2'b00时,out被赋值为0;当sel等于2'b01时,out被赋值为1;当sel等于2'b10或2'b11时,out被赋值为2;如果sel的值不匹配任何给定的情况,则执行默认的语句将out赋值为0。

5. 编码

5.1. 格雷码

格雷码:格雷码是一种二进制编码方式,其中相邻的两个状态只有一个位的差异。这种编码方式在状态转换时只有一个位发生变化,因此可以有效地减少状态转换过程中可能引起的冲突和震荡问题。格雷码的主要特点是每个状态只有一个位为1,其余位都为0。例如,对于3个状态的状态机,使用格雷码编码如下:

状态

格雷码

00

00

01

01

10

11

格雷码编码对于设计具有较大状态数量的状态机非常有用,因为它可以减少硬件资源的使用量,并提高系统的可靠性。

5.2. 独热码

独热码:独热码也是一种二进制编码方式,其中每个状态都有唯一的编码,只有一个位为1,其余位为0。这种编码方式使得每个状态之间的转换更加简单和直观。但是,当状态数量增加时,独热码的硬件资源使用量也会随之增加。对于状态机具有较少状态数量且要求直观的状态编码时,独热码是一个不错的选择。

例如,对于3个状态的状态机,使用独热码编码如下:

状态

独热码

00

100

01

010

10

001

6. 状态机

在Verilog中,状态机是描述系统行为的重要构建块之一。它可以通过组合逻辑或时序逻辑的方式实现,并且通常包含以下几类状态机:

6.1. Moore状态机

在Moore状态机中,输出仅取决于当前状态。状态转移和输出逻辑是分离的。当状态转移发生时,输出信号保持不变直到进入下一个状态。Moore状态机更加简单、易于设计和理解。以下是一个使用Moore状态机实现的示例:

module MooreStateMachine (
  input clk,
  input reset,
  output reg out
);

  typedef enum logic [1:0] {
    STATE_A,
    STATE_B,
    STATE_C
  } state_t;

  reg [1:0] current_state, next_state;

  always @(posedge clk or posedge reset)
    begin
      if (reset) begin
        current_state <= STATE_A;
      end
      else begin
        current_state <= next_state;
        case (current_state)
          STATE_A: begin
            next_state = STATE_B;
          end

          STATE_B: begin
            next_state = STATE_C;
          end

          STATE_C: begin
            next_state = STATE_A;
          end

          default: begin
            next_state = STATE_A;
          end
        endcase
      end
    end

  always @(current_state)
    begin
      case (current_state)
        STATE_A: begin
          out = 0;
        end

        STATE_B: begin
          out = 1;
        end

        STATE_C: begin
          out = 1;
        end

        default: begin
          out = 0;
        end
      endcase
    end
endmodule

6.2. Mealy状态机

与Moore状态机相反,Mealy状态机的输出除了依赖于当前状态,还取决于输入信号。因此,输出可以在状态转移过程中发生变化。以下是一个使用Mealy状态机实现的示例:

module MealyStateMachine (
  input clk,
  input reset,
  input in,
  output reg out
);

  typedef enum logic [1:0] {
    STATE_A,
    STATE_B,
    STATE_C
  } state_t;

  reg [1:0] current_state, next_state;

  always @(posedge clk or posedge reset)
    begin
      if (reset) begin
        current_state <= STATE_A;
      end
      else begin
        current_state <= next_state;
        case (current_state)
          STATE_A: begin
            if (in == 1'b1) begin
              next_state = STATE_B;
            end
            else begin
              next_state = STATE_C;
            end
          end

          STATE_B: begin
            if (in == 1'b0) begin
              next_state = STATE_A;
            end
            else begin
              next_state = STATE_C;
            end
          end

          STATE_C: begin
            if (in == 1'b1) begin
              next_state = STATE_A;
            end
            else begin
              next_state = STATE_B;
            end
          end

          default: begin
            next_state = STATE_A;
          end
        endcase
      end
    end

  always @(current_state or in)
    begin
      case (current_state)
        STATE_A: begin
          if (in == 1'b0) begin
            out = 0;
          end
          else begin
            out = 1;
          end
        end

        STATE_B: begin
          if (in == 1'b0) begin
            out = 1;
          end
          else begin
            out = 0;
          end
        end

        STATE_C: begin
          if (in == 1'b0) begin
            out = 1;
          end
          else begin
            out = 1;
          end
        end

        default: begin
          out = 0;
        end
      endcase
    end
endmodule

6.3. 异步状态机

这种状态机可以处理来自异步输入源的不同时间延迟和频率的信号。异步状态机需要考虑到可能存在的冲突和不确定性。在Verilog中,异步状态机通常使用组合逻辑和if语句来实现状态转移和输出逻辑。以下是一个简单的异步状态机示例:

module AsynchronousStateMachine (
  input reset,
  input in1,
  input in2,
  output reg out
);

  typedef enum logic [1:0] {
    STATE_A,
    STATE_B,
    STATE_C
  } state_t;

  reg [1:0] current_state, next_state;

  always @*
    begin
      if (reset) begin
        current_state = STATE_A;
      end
      else begin
        case (current_state)
          STATE_A: begin
            if (in1 && !in2) begin
              next_state = STATE_B;
            end
            else if (!in1 && in2) begin
              next_state = STATE_C;
            end
            else begin
              next_state = STATE_A;
            end
          end

          STATE_B: begin
            if (!in1 || in2) begin
              next_state = STATE_A;
            end
            else begin
              next_state = STATE_B;
            end
          end

          STATE_C: begin
            if (!in2 || in1) begin
              next_state = STATE_A;
            end
            else begin
              next_state = STATE_C;
            end
          end

          default: begin
            next_state = STATE_A;
          end
        endcase
      end
    end

  always @(current_state)
    begin
      case (current_state)
        STATE_A: begin
          out = 0;
        end

        STATE_B: begin
          out = 1;
        end

        STATE_C: begin
          out = 1;
        end

        default: begin
          out = 0;
        end
      endcase
    end
endmodule

7. 竞争和冒险

7.1. 概念

在数字电路设计中,信号传输或者状态变换时在硬件电路上都会有一定的延时。

在组合逻辑电路中,不同路径的输入信号变化传输到同一点门级电路时,在时间上有先有后,这种先后所形成的时间差导致输出产生不应有的尖峰干扰脉冲的现象叫做竞争。

由于竞争的存在,输出信号需要经过一段时间才能达到期望状态,过渡时间内可能产生瞬间的错误输出,这种现象被称为冒险。

竞争不一定有冒险,但冒险一定会有竞争。

7.2. 示例

例如,对于给定逻辑 out = in1 & in0',电路如图所示:

波形:

可以看到,由于in0/in1到AND gate输入pin上delay的不匹配,导致AND的输出out出现一个logic 1的小脉冲,一般也叫毛刺(glitch)。

对于一个简单的AND gate,就会产生毛刺;那么对于一个更复杂的电路,比如:加法器,乘法器,glitch更是起起伏伏,直到一定的时间后,才会输出稳定的值。

这就是信号的竞争与冒险:逻辑上(真值表)输入的变化本来不会导致组合逻辑输出的变化;但是因为在输入逻辑gate的PIN上,输入信号变化时间上的差异,导致组合逻辑的输出端产生一些不必要的0-->1/1-->0变化,出现glitch。

7.3. 消除竞争冒险

消除竞争冒险的几个方法:

  1. 加封锁脉冲。在输入信号产生竞争冒险的时间内,引入一个脉冲将可能产生尖峰干扰脉冲的门封锁住。封锁脉冲应在输入信号转换前到来,转换结束后消失。
  2. 加选通脉冲。对输出可能产生尖峰干扰脉冲的门电路增加一个接选通信号的输入端,只有在输入信号转换完成并稳定后,才引入选通脉冲将它打开,此时才允许有输出。在转换过程中,由于没有加选通脉冲,因此,输出不会出现尖峰干扰脉冲。
  3. 接入滤波电容。由于尖峰干扰脉冲的宽度一般都很窄,在可能产生尖峰干扰脉冲的门电路输出端与地之间接入一个容量为几十皮法的电容就可吸收掉尖峰干扰脉冲。
  4. 修改逻辑设计,增加冗余项。利用卡诺图,在两个相切的圆之间,增加一个卡诺圈,并加在逻辑表达式之中。
  5. 同步电路信号的变化都发生在时钟边沿。对于触发器的 D 输入端,只要毛刺不出现在时钟的上升沿并且不满足数据的建立和保持时间,就不会对系统造成危害,因此可认为 D 触发器的 D 输入端对毛刺不敏感。 利用此特性,在时钟边沿驱动下,对一个组合逻辑信号进行延迟打拍,可消除竞争冒险。延迟一拍时钟时,会一定概率地减少竞争冒险的出现。实践表明,最安全的打拍延迟周期是 3 拍,可有效减少竞争冒险的出现。
  6. 采用格雷码计数器,计数时相邻的数之间只有一个数据 bit 发生了变化,所以能有效的避免竞争冒险。

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

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

相关文章

Delphi Web和Web服务开发目前有哪些选择

Delphi Web和Web服务开发目前有哪些选择 Delphi Web和Web服务开发目前有以下几个选择&#xff1a; Delphi MVC Framework&#xff08;https://github.com/delphimvcframework/delphimvcframework&#xff09;&#xff1a;这是一个开源的Delphi Web框架&#xff0c;基于MVC&am…

小程序uniapp关闭手势返回操作

需求&#xff1a;进入当前页面后&#xff0c;无法返回其他页面&#xff0c;禁止所有返回操作&#xff08;手势返回、左上角返回按钮等&#xff09; 解决&#xff1a; 方法一&#xff1a;wx.enableAlertBeforeUnload wx.enableAlertBeforeUnload 在onLoad里调用&#xff1a; on…

-isystem isystem 实验记录

1&#xff0c;isystem 的理论 2&#xff0c;实验方案 $ tree . ├── inc111 │ └── test.h ├── inc222 │ └── test.h └── src ├── a.out └── hello.c inc111/test.h: #pragma once#define NUM 111 inc222/test.h #pragma once#define N…

2024年9月中国数据库排行榜:openGauss系多点开花,根社区优势明显

在墨天轮发布的9月中国数据库流行度排行榜中&#xff0c;中国数据库产业格局进一步聚集刷新&#xff0c;呈现出3大显著特征&#xff1a; 开源势力力争上游显优势领先潮流&#xff1b;openGauss 开源根社区优势明显&#xff1b;阿里华为两极鼎立云上云下各争先&#xff1b; 开…

2024年第二届《英语世界》杯全国大学生英语听力大赛

下周开考&#xff01; 一、主办单位 商务印书馆《英语世界》杂志社 二、时间安排 赛事报名时间&#xff1a;即日起-2024年11月15日 正式比赛阶段&#xff1a;第一场&#xff1a;2024年9月22日10:00-22:00 第二场&#xff1a;2024年10月27日10:00-22:00 第三场&#xff1…

安装2024最新版Android Studio 最详细教程(带图展示)

一、安装JDK &#xff08;1&#xff09;首先在除C盘以外的盘建立文件夹&#xff0c;分别保存软件位置&#xff0c;JDK位置与SDK位置&#xff0c; 特别注意&#xff1a;所有文件名中不要出现空格&#xff0c;而且每个文件夹都是为空的状态 这里我是在D盘中操作。 &#xff0…

综合型医院适合什么样的数据摆渡方式,才能服务与安全兼顾?

综合型医院&#xff0c;是提供全面医疗服务的综合型医院。综合型医院的服务对象广泛&#xff0c;包括儿童、成人、老年人等各年龄段的人群&#xff0c;以及患有各种疾病的患者。它们通过提供全面的医疗服务&#xff0c;保障人民群众的健康需求&#xff0c;是医疗卫生事业的重要…

IP-adapter masking

https://github.com/huggingface/diffusers/issues/6802https://github.com/huggingface/diffusers/issues/6802

Java后端编程语言进阶篇

第一章 函数式接口 函数式接口是Java 8中引入的一个新特性&#xff0c;只包含一个抽象方法的接口。 函数式接口可以使用Lambda表达式来实现&#xff0c;从而实现函数式编程的特性。 使用 FunctionalInterface标识接口是函数式接口&#xff0c;编译器才会检查接口是否符合函数…

linux-L3-linux 复制文件

linux 中要将文件file1.txt复制到目录dir中&#xff0c;可以使用以下命令 cp file1.txt dir/复制文件 cp /path/to/source/file /path/to/destination移动 mv /path/to/source/file /path/to/destination复制文件夹内的文件 cp -a /path/to/source/file /path/to/destinati…

孟德尔随机化分析和GWAS分析有什么区别?

大家好&#xff0c;我是邓飞。 最近一直在研究孟德尔随机化分析&#xff0c;已经从概念到实操了&#xff0c;程序已经跑通了&#xff0c;很开心。这几天写的博客&#xff1a; 孟德尔随机化的术语理解 从一篇孟德尔随机化文章看MR常见结果形式 对于GWAS分析&#xff0c;从原…

LRELHLNNN;亲水性抗肝纤维化多肽作为基础肽;I型胶原蛋白靶向肽;九肽LRELHLNNN

【LRELHLNNN 简介】 LRELHLNNN是一种多肽&#xff0c;它能够选择性地结合到I型胶原蛋白&#xff0c;具有亲和力为170 nM。LRELHLNNN是由9个氨基酸组成&#xff0c;其氨基酸序列为H-Leu-Arg-Glu-Leu-His-Leu-Asn-Asn-Asn-OH。LRELHLNNN因其与I型胶原蛋白的高亲和力而在生物医学领…

密码学---黄道十二宫

✨简单理解的概念&#xff1a;是一种换位密码。 &#x1f380;破解需要用到对角线的方式&#xff1a;第一个H&#xff0c;先向下移动1位&#xff0c;再向右移动2位&#xff0c;依次类推。 &#x1f380;接着对对角线重新排列&#xff0c;就能得到一段有序的代码 &#x1f380; …

玩机搞机-----如何简单的使用ADB指令来卸载和冻结系统应用 无需root权限 详细操作图示教程

同类博文&#xff1a; 玩机搞机---卸载内置软件 无root权限卸载不需要的软件 安全卸载_无需root卸载彻底内置软件-CSDN博客 在很多时候我们需要卸载一些系统级的app。但如果直接手机端进行卸载的话。是无法正常卸载的。其实我们可以通过有些成品工具或者完全靠ADB指令来进行卸…

网红酒店|基于java的网红酒店预定系统(源码+数据库+文档)

酒店预定|网红酒店|网红酒店预定系统 目录 基于java的网红酒店预定系统 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&am…

4×4矩阵键盘详解(STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.工作原理介绍 三、程序设计 main.c文件 button4_4.h文件 button4_4.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 ​​​​​矩阵键盘&#xff0c;又称为行列式键盘&#xff0c;是用4条I/O线作为行线&#xff0c;4…

【四范式】浅谈NLP发展的四个范式

自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;是计算机科学&#xff0c;人工智能&#xff0c;语言学关于计算机和人类自然语言之间的相互作用的领域&#xff0c;是计算机科学领域与人工智能领域中的一个重要方向。NLP发展到今天已经进入到了…

[Python学习日记-19] 细讲数据类型——集合

[Python学习日记-19] 细讲数据类型——集合 简介 集合的创建 集合的增删查 集合的循环 集合的去重 集合的关系运算 简介 在前面我们学习到了列表、元组、字符串、字典这几种数据类型&#xff0c;在 Python 中还有最后一种数据类型&#xff0c;那就是集合&#xff0c;下面…

Cloudflare Pages 部署 Next.js 应用教程

Cloudflare Pages 部署 Next.js 应用教程 本教程将指导你如何将现有的 Next.js 应用部署到 Cloudflare Pages。 准备工作 安装部署依赖 首先,安装 cloudflare/next-on-pages: npm install --save-dev cloudflare/next-on-pages添加 wrangler.toml 配置文件 在项目根目录创建 …

如何删除git提交记录

今天在提交github时&#xff0c;不小心提交了敏感信息&#xff0c; 不要问我提交了啥&#xff0c;问就是不知道 查了下资料&#xff0c;终于找到简单粗暴的方式来删除提交记录。方法如下 git reset --soft HEAD~i i代表要恢复到多少次提交前的状态&#xff0c;如指定i 2&…