SV学习笔记(四)

OCP Open Closed Principle 开闭原则

文章目录

  • 随机约束和分布
    • 为什么需要随机?
    • 为什么需要约束?
    • 我们需要随机什么?
    • 声明随机变量的类
    • 什么是约束
    • 权重分布
    • 集合成员和inside
    • 条件约束
    • 双向约束
  • 约束块控制
    • 打开或关闭约束
    • 内嵌约束
  • 随机函数
    • pre_randomize 和 post_randomize
    • 系统随机数函数
    • 随机化个别变量
  • 数组约束
    • 约束数组的大小
    • 约束数组的元素
    • 产生唯一元素值的数组
    • 随机化句柄数组
  • 随机控制
  • 参考资料

随机约束和分布

为什么需要随机?

  • 芯片复杂度越来越高,在20年前 定向测试 已经无法满足验证的需求,而 随机测试 的比例逐渐提高。
  • 定向测试能找到你认为可能存在的缺陷,而 随机测试可以找到连你都没有想到的缺陷 。
  • 随机测试的环境要求比定向测试复杂,它需要激励、参考模型和在线比较。上百次的仿真不再需要人为参与,以此来提高验证效率。
  • 随机测试相对于定向测试可以减少相当多的代码量,而产生的激励较定向测试也更多样

为什么需要约束?

  • 如果随机没有约束,产生有效激励的同时,还 会产生大量的无效激励
  • 通过为随机添加约束,这种 随机自由是一种合法的随机 ,产生有效的测试激励。
  • 约束不是一成不变的,为了获取期望的测试范围或期待的数值范围,约束需要“变形”。
  • 随机的对象不只是一个数据,而是 有联系的变量集合 。通常这些变量集合会被封装在一个数据类里,同时需要类中声明数据之间的约束关系。因此,约束之后要产生一个随机数据的“求解器”,即在满足数据本身和数据之间约束关系的随机数值解。
  • 约束不但 可以指定数据的取值范围 ,还 可以指定各个数值的随机权重分布

我们需要随机什么?

  • 器件配置: 通过寄存器和系统信号
  • 环境配置: 随机化环境,例如合理的时钟和外部反馈信号。
  • 原始输入数据: 例如MCDF数据包的长度、带宽,数据间的顺序。
  • 延时: 握手信号之间的时序关系,例如valid和ready,req和ack之间的时序关系。
  • 协议异常: 如果反馈信号给出异常,那么设计是否可以保持后续数据处理的稳定性。

声明随机变量的类

  • 随机化是为了产生更多可能的驱动,我们倾向于将相关数据有机整理在一个类的同时,也用“rand”关键词来表明它的随机属性。
  • “randc”关键词表示周期性随机,即所有可能的值都赋过值后随机才可能重复,也就好比54张扑克牌抽牌游戏,rand代表每抽完一张放回去才可以下次抽牌,randc代表没抽完一张不需要放回就抽取下一张,如果抽完了,那就全部放回再次同样规则抽取。
  • rand和randc,只能声明类的变量,硬件域以及软件域的局部变量都不可以
  • 随机属性需要配合SV预定义的随机函数std::randomize()使用即通过声明rand变量,并且在后期调用randomize()函数才可以随机化变量。
  • 约束constraint也同随机变量一起在class中声明。
class packet;rand bit [31:0] src, dst, data[8];randc bit [7:0] kind;constraint c {src >10;src <15;}
endclass//----------------------------------Packet p;
initial beginp = new();//assert语句保证randomize成功,否则会报fatal(如果约束冲突,如src>15 and src<10则会随机失败)assert (p.randomize()) else $fatal(0, "Packet::randomize failed");transmit(p);
end

白话一刻

* `class packet;`:定义一个名为`packet`的类。  
* `rand bit [31:0] src, dst, data[8];`:声明了三个随机变量,分别是`src`(源地址)、`dst`(目标地址)和`data`(一个包含8个元素的数组,用于存储数据)。每个变量的位宽度为32位。  
* `randc bit [7:0] kind;`:声明了一个随机且唯一的变量`kind`,其位宽度为8位。`randc`意味着每次生成的`kind`值都是唯一的,直到所有可能的值都被使用完。  
* `constraint c { ... }`:定义了一个约束`c`,用于限制随机变量的取值范围或关系。这里,它指定了`src`的值必须大于10且小于15。
* `Packet p;`:声明了一个`packet`类型的变量`p`。注意,这里类名`packet`的首字母是大写的,这通常表示它是一个用户定义的类型,而不是SystemVerilog的内建类型。  
* `initial begin ... end`:`initial`块在仿真开始时执行一次。  + `p = new();`:创建一个新的`packet`对象,并将其赋值给变量`p`。  + `assert (p.randomize()) else $fatal(0, "Packet::randomize failed");`:调用`p`的`randomize`方法,该方法会根据类的约束随机设置`p`的成员变量的值。`assert`语句检查`randomize`是否成功。如果`randomize`失败(例如,由于约束冲突),则执行`else`部分的`$fatal`语句,导致仿真终止并输出错误消息。  + `transmit(p);`:调用一个名为`transmit`的函数(这个函数在提供的代码片段中未定义),并将随机化的数据包`p`作为参数传递。

总之,这段代码定义了一个数据包类,并展示了如何创建和随机化这个类的实例,以及如何将这个实例传递给一个函数。这对于在仿真中生成随机化的数据包场景非常有用。

什么是约束

  • 约束表达式的求解是有SV的约束求解器自动完成的
  • 求解器能够选择满足约束的值,这个值是由SV的PRNG(伪随机数发生器)从一个初始值(seed)产生。只要改变种子的值,就可以改变CRT的行为。
  • SV标准定义了表达式的含义以及产生的合法值,但没有规定求解器计算约束的准确顺序。也就是,不同仿真器对于同一个约束类和种子求解出的数值可能不同。
  • 什么可以被约束?SV只能随机化二值数据类型,但数据位可以是二值或四值的,所以无法随机出x值和z值,也无法随机出字符串。
class date;rand bit [2:0] month; //note:rand bit [4:0] day;rand int year;constraint c_data {month inside {[1:12]};day inside {[1:31]};year inside {[2010:2030]};}}
endclass

请问:month=10,day=31,year=2020此组随机值可以产生吗?

答案:不能,因为month的声明是3位,所以不可能出现数值10,这也是经常会犯的错误,当你约束数据时,一定要与声明数据的位数相匹配。

class stim;const bit [31:0] CONGEST_ADDR = 42; //声明常数typedef enum {READ, WRITE, CONTROL} stim_e;randc stime_e kind;rand bit [31:0] len, src, dst;bit congestion_test;constraint c_stim {len < 1000;len > 0;if(congestion_test) (dst inside {[CONGEST_ADDR-100:CONGEST_ADDR+100]};src == CONGEST_ADDR;) else (src inside {0, [10:20], [100:200]};)}
endclass

权重分布

  • 关键词dist可以在约束中用来产生随机数值的权重分布,这样某些值的选取机会要大于其他值。
  • dist操作符带有一个值的列表以及相应的权重,中间用 := 或 😕 分开。值和权重可以是常数,也可以是变量。
  • 权重不要百分比表示,权重的和也不必是100。
  • := 操作符表示值的范围内的每一个值的权重是相同的, 😕 操作符表示权重要平均分到范围内的每一个值。
rand int src, dst;constraint c_dist {src dist {0:=40, [1:3]:=60;}// src=1, weight=40/220// src=2, weight=60/220// src=3, weight=60/220// src=4, weight=60/220dst dist {0:/40, [1:3]:/60;}// dst=1, weight=40/100// dst=2, weight=20/100// dst=3, weight=20/100// dst=4, weight=20/100
}

这段代码是使用SystemVerilog语言编写的,用于定义随机数生成的约束。SystemVerilog通常用于硬件描述和验证。下面我将详细解释这段代码:systemverilog
rand int src, dst;
这行代码声明了两个随机整数变量:src 和 dst。rand 关键字表示这些变量在仿真期间可以被随机化。systemverilog
constraint c_dist {  src dist {0:=40, [1:3]:=60;}  dst dist {0:/40, [1:3]:/60;}  
}
这部分定义了一个名为 c_dist 的约束,用于控制 src 和 dst 变量的随机化分布。对于 src 变量:systemverilog
src dist {0:=40, [1:3]:=60;}
{0:=40} 表示当 src 变量取值为 0 时,其权重是 40。
{[1:3]:=60} 表示当 src 变量取值为 1、2 或 3 时,其权重是 60。
权重可以理解为生成特定值的概率或可能性。权重越高,生成该值的概率越大。对于 dst 变量:systemverilog
dst dist {0:/40, [1:3]:/60;}
{0:/40} 表示当 dst 变量取值为 0 时,其权重是 40。
{[1:3]:/60} 表示当 dst 变量取值为 1、2 或 3 时,其权重是 60。
注意,src 和 dst 的权重分布使用了不同的语法。src 使用了 := 运算符,而 dst 使用了 :/ 运算符。这实际上是一个语法错误,因为在SystemVerilog中,权重分布应该使用统一的语法。通常,你会看到 := 用于指定绝对权重,而 :/ 用于指定相对权重。但在同一个约束中混合使用这两种语法是不正确的。此外,注释部分解释了每个值的权重分布,但它似乎有些混淆,因为它似乎试图将权重与可能的取值范围相除来得到概率,但这不是正确的解释。实际上,权重是独立的数值,它们会被归一化以表示生成特定值的相对概率。正确的解释应该是:对于 src,总权重是 40 + 60 * 3 = 220。因此,src 取值为 0 的概率是 40/220,取值为 1、2 或 3 的概率是 60/220。
对于 dst,由于代码中的语法错误,我们不能直接计算权重分布。如果假设 dst 也使用绝对权重,并且语法被修正为 dst dist {0:=40, [1:3]:=60};,那么总权重将是 100(因为权重被错误地标记为相对权重)。但实际上,dst 的权重分布应该也使用绝对权重,并且总和应该与 src 一致,以便进行正确的概率计算。
为了修复这个问题,你应该选择使用绝对权重或相对权重,并确保 src 和 dst 的权重分布语法一致。如果你使用绝对权重,代码应该类似于:systemverilog
rand int src, dst;  constraint c_dist {  src dist {0:=40, [1:3]:=20}; // 总权重为 80  dst dist {0:=40, [1:3]:=20}; // 总权重也为 80,以保持一致性  
}
这样,src 和 dst 就会有相同的权重分布,每个值都有相同的概率被选中。

集合成员和inside

  • inside是常见的约束运算符,表示变量属于某个值的集合,除非还存在其他约束 ,否则随机变量在集合里取值的概率是相等的(集合里也可以是变量)。
  • 可以使用 $ 符指定最大或最小值。
rand int c;
int lo, hi;
constraint c_range{c inside {[lo:hi]};
}//-------------------------------rand bit [6:0] b;
rand bit [5:0] e;
constraint c_range {b inside {[$:4], [20:$]};e inside {[$:4], [20:$]};
}

条件约束

可以通过 -> 或者 if-else来让一个约束表达式在特定条件有效。

constraint c_io {(i_space_mode) -> addr[31] == 1'b1; //i_space_mode!=0
}//--------------------------------------constraint c_io {if(i_space_mode) //i_space_mode!=0addr[31] == 1'b1;else;
}

双向约束

  • 约束块不是自上而下的程序代码,它们是声明性代码,是并行的,所有的约束同时有效。
  • 约束是双向的,这表示它会同时计算所有的随机变量的约束,增加或删除任何一个变量的约束都会直接或间接的影响所有相关的值的选取。
  • 约束块可以声明多个,但是它们仍旧是并行的,如果对同一变量进行约束,取两者约束的交集,也就是两个约束都会生效,与写在一个约束块效果相同。
  • 子类会继承父类的约束。

约束块控制

打开或关闭约束

  • 一个类可以包含多个约束块,可以把不同约束块用于不同测试。

  • 一般情况下,各个约束块之间的约束内容是相互协调不违背的,因此通过随机函数产生的随机数可以找到合适的解。

  • 对于其他情况,例如跟胡不同需求,来选择使能哪些约束块,禁止哪些约束块,可以使用内建函数constraint_mode()打开或者关闭约束。

class packet;rand int length;constraint c_short {length inside {[1:32];}}constraint c_long {length inside {[1000:1032];}}
endclass//------------------------packet p;
initial beginp =new ();//create a long packet by disabling c_shortp.c_short.constraint_mode(0);assert(p.randomize());transmit(p);//create a short packet by disabling all constraint and then enable only c_shortp.constraint_mode(0);p.c_short.constraint_mode(1);assert(p.randomize());transmit(p);
end

内嵌约束

  • 伴随着复杂的约束,它们之间会相互作用,最终产生难以预测的结果。用来使能和禁止这些约束的代码也会增加测试的复杂性。
  • 经常增加或修改类的约束也可能会影响整个团队的工作,这需要考虑类的OCP原则(开放封闭原则,也就是哪些对外部开放,哪些不对外开放)。
  • SV允许使用 randomize() with来增加额外的约束,这和在类里增加约束是等效的,但同时要注意类内部约束和外部约束之间应该是协调的,如果出现违背,随机数会求解失败(求解失败,不同的工具报告形式不同,有的是error,有的是warning)。
class packet;rand int length;constraint c_short {soft length inside {[1:32];}}
endclass//------------------------packet p;
initial beginp =new ();assert(p.randomize() with {length inside {[36:46];};length != 40;         });transmit(p);
end

上述例子中randomize() with{}约束与c_short产生可冲突,那会不会报错呢?

答案是不会,因为c_short约束前加了soft(软约束)关键字,意义就在于当外部或子类的约束发生冲突时,其优先级降低,不会影响外部或子类的约束。

随机函数

pre_randomize 和 post_randomize

  • 有时需要在调用randomize()之前或之后立即执行一些操作,例如在随机前设置一些非随机变量(上下限、条件值、权重),或者在随机化后需要计算数据的误差、分析和记录随机数据等。

  • SV提供两个预定义的void类型函数pre_randomize和post_randomize,用户可以类中定义这两个函数,分别在其中定义随机化前的行为和随机化后的行为。

  • 如果某个类中定义了pre_randomize或post_randomize,那么对象在执行randomize()之前或之后会分别执行这两个函数,所以pre_randomize和post_randomize可以看做是randomize函数的回调函数(callback function)。

和之前学的语言类的知识关联起来了,好像spring框架的前置和后置

系统随机数函数

SV提供了一些常用的系统随机函数,这些系统随机函数可以直接调用来返回随机数值:

  • $random()平均分布,返回32位有符号随机数。
  • $urandom()平均分布,返回32位无符号随机数。
  • $urandom_range()在指定范围内的平均分布。

随机化个别变量

  • 在调用randomize()时可以传递变量的一个子集,这样只会随机化类里的几个变量。
  • 只有参数列表里的变量才会被随机化,其他变量会被当做状态量而不会被随机化。
  • 所有的约束仍然保持有效。
  • 注意:类里所有没有被指定rand的变量也可以作为randomize()的参数而被随机化。
  • 注意:未进行随机化的变量默认初始值为0。
class rising;byte low;rand byte med, hi;constraint up {low<med; med<hi;}
endclass//----------------------------------initial beginrising r;r =new();r.randomize(); //随机化hi和med,不改变lowr.randomize(med); //只随机化medr.randomize(low); //只随机化low
end

数组约束

约束数组的大小

  • 在约束随机标量的同时,我们也可以对随机化数组进行约束。
  • 多数情况下,数组的大小应该给定范围,防止生成过大体积的数组或空数组。
  • 此外,还可以在约束中结合数组的其他方法sum(), product(), and(), or(), 和xor()。
class dyn_size;rand logic [31:0] d[];constraint d_size {d,size() inside {[1:10];};}
endclass

约束数组的元素

  • SV可以利用foreach对数组每一个元素进行约束,和直接写出对固定大小数组的每一个元素相比,foreach更简洁。
  • 针对动态数组,foreach更适合于对非固定大小数组中每个元素的约束。
class good_sum5;rand uint len[];constraint c_len{foreach (len[i]) len[i] inside {[1:255]};len.sum() < 1024;len.size() inside {[1:8]};}
endclass

产生唯一元素值的数组

如果想要产生一个随机数组,它的每一个元素值都是唯一的,如果使用randc数组,数组中的每一个元素只会独立的随机化,并不会按照我们期望的使得数组中的元素值是唯一的。

解决方案1:

rand bit [7:0] data;
constraint c_data{foreach(data[i])foreach(data[j])if(i != j) data[i] != data[j];
}

解决方案2:

class randc_data;randc bit [7:0] data[64];
endclassclass data_array;bit [7:0] data_array [64];function void pre_randomize();randc_data rcd;rcd = new();foreach (data_array[i]) beginassert(rcd.randomize());data_array[i] = rcd.val;endendfunction
endclass

“randc”关键词表示周期性随机,即所有可能的值都赋过值后随机才可能重复,也就好比54张扑克牌抽牌游戏,rand代表每抽完一张放回去才可以下次抽牌,randc代表没抽完一张不需要放回就抽取下一张,如果抽完了,那就全部放回再次同样规则抽取。

  • 特别示例如下,首先“<=”代表小于等于,其次限定da.size为(3/4/5),实际不可能取到5,原因是da.size的约束体现在“da[i] <= da[i+1]”时,约束的是i和i+1为(3/4/5)。
rand bit [7:0] da[];
constraint c_da {da.size() inside {[3:5]};foreach(da[i]) da[i] <= da[i+1];
}

随机化句柄数组

  • 随机句柄数组的功能是在调用其所在类的随机函数时,随机函数会随机化数组中的每一个句柄所指向的对象。因此随机句柄数组的声明一定要添加rand来表示其随机化的属性,同时在调用随机函数前要保证句柄数组中的每一个句柄元素都是非悬空的,这需要早随机化之前为每一个元素句柄构建对象。

  • 如果要产生多个随机对象,那么你可能需要建立随机句柄数组。和整数数组不同,你需要在随机化前分配所有的元素,因为在随机求解器不会创建对象。使用动态数组可以按照需要分配最大数量的元素,然后再使用约束减小数组的大小。在随机化时,动态句柄数组的大小可以保持不变或减小,但不能增加。

parameter MAX_SIZE = 10;
class RandStuff;bit[1:0] value = 1;
endclassclass RandArray;rand RandStuff array[];constraint c_array {array.size() inside {[1:MAX_SIZE]};}function new();//分配最大容量array = new[MAX_SIZE];foreach (array[i]) array[i] = new();endfunction
endclass//---------------------------RandArray ra;
initial begin// 构造数组和所有对象ra = new();// 随机化数组,但可能会减小数组assert(ra.randomize());foreach(ra.array[i]) $display(ra.array[i].value);
end
  • 问题1:执行ra.randomize() with {array.size=2}时,array[0].value 和 array[0].value分别是多少?

答案都是1,首先value没有加rand,所以randomize不会随机value,仍然保持为1。

  • 问题2:为什么要分配最大容量?

答案是只有创建对象,并且分配最大容量,才能保证随机化时可能会碰到句柄数组悬空,无指向对象,随机会报错。

  • 总结:句柄数组的随机,首先查看句柄指向的对象内有没有rand变量,其次对句柄数组按最大容量进行例化

随机控制

  • 产生事务序列的另一个方法是使用SV的randsequence结构。这对于随机安排组织原子(atomic)测试序列很有帮助。
initial beginfor (int i=0; i<15; i++) beginrandsequence (stream)stream: cfg_read := 1 | //权重不一样io_read := 2  | //权重不一样mem_read := 5; //权重不一样cfg_read: (cfg_read_task;) |(cfg_read_task;) cfg_read;mem_read: (mem_read_task;) |(mem_read_task;) mem_read;io_read: (io_read_task;) |(io_read_task;) io_read;endsequenceend
end

这是一个伪代码或特定于某个工具(如SystemVerilog)的代码片段,用于描述一种随机序列生成机制。我会逐步解释这段代码的含义。

  • initial begin
    initial 是 SystemVerilog 中的一个块,它在仿真开始时就执行一次。begin … end 是定义该块范围的关键词。

    1. for (int i=0; i<15; i++) begin … end

这是一个循环结构,它将执行其内部的代码块 15 次。每次迭代,i 的值从 0 增加到 14。

    1. randsequence (stream)

randsequence 是 SystemVerilog 中用于描述随机序列的关键字。它允许用户为某个事件流(在这里是 stream)定义多个可能的随机序列。

    1. stream: cfg_read := 1 | io_read := 2 | mem_read := 5;

这定义了三个事件:cfg_read、io_read 和 mem_read,并分别为它们分配了权重。权重决定了这些事件在随机选择时出现的频率。例如,mem_read 事件出现的频率是 cfg_read 的 5 倍,是 io_read 的 2.5 倍。

    1. cfg_read: (cfg_read_task;) | (cfg_read_task;) cfg_read;

这定义了当 cfg_read 事件被选择时要执行的任务或操作。这里,cfg_read_task 被执行,然后事件流可以选择再次进入 cfg_read 状态(通过后面的 cfg_read)或者退出这个状态(因为有两个选择,但只执行一个)。

    1. mem_read: (mem_read_task;) | (mem_read_task;) mem_read;

与 cfg_read 类似,但这里是为 mem_read 事件定义的行为。

    1. io_read: (io_read_task;) | (io_read_task;) io_read;

同样,这是为 io_read 事件定义的行为。

  • 总结:

这段代码描述了一个循环,该循环运行 15 次。在每次迭代中,它都会根据定义的权重随机选择一个事件(cfg_read、io_read 或 mem_read)并执行相应的任务。

每个事件都有自己的任务(cfg_read_task、mem_read_task 和 io_read_task),并且在任务执行完毕后,可以选择再次进入相同的事件或退出。

这种随机性在模拟或测试复杂系统的行为时非常有用,因为它可以模拟多种可能的执行顺序或条件。

  • 我们也可以使用randcase来建立随机决策树,但它带来的问题是没有变量可供追踪调试。
initial beginint len;randcase:1: len = $urandom_range(0,2); //10%8: len = $urandom_range(3,5); //80%1: len = $urandom_range(6,7); //10%endcase$display("len=%0d", len);
end
  • 总结:
    • randsequence和randcase是针对轻量级的随机控制的应用。而我们可以通过定义随机类取代上述随机控制的功能,并且由于类的继承性使得后期维护代码时更加方便。
    • randsequence的相关功能我们在协调激励组件和测试用例时,可能会用到。
    • randcase则对应着随机约束中的dist权重约束 + if-else条件约束的组合。

参考资料

  • Wenhui’s Rotten Pen
  • SystemVerilog
  • chipverify

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

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

相关文章

LeetCode-131. 分割回文串【字符串 动态规划 回溯】

LeetCode-131. 分割回文串【字符串 动态规划 回溯】 题目描述&#xff1a;解题思路一&#xff1a;回溯&#xff0c; 回溯三部曲解题思路二&#xff1a;0解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个…

微信小程序中选中手机相册图片上传到服务器的方法

思路&#xff1a; 实现图片上传我们需要使用chooseImg和uploadFile这两个api。 1. 微信小程序中的chooseImg是一个API&#xff0c;用于在用户相册或相机中选择图片上传。它可以让用户在小程序中选择上传图片&#xff0c;以便进行下一步操作&#xff0c;例如将其发送给朋友或将其…

vue项目安装下载项目包,报错Clear up some disk space and try again

npm install 报错&#xff1a; Clear up some disk space and try again 解决办法&#xff1a; npm cache clean --force npm cache clear --force && npm install --no-shrinkwrap --update-binary

常用软件架构模式优缺点及应用场景

1、分层架构模式 最常见的架构模式就是分层架构或者称为 n 层架构。大部分软件架构师、设计师和开发者都对这个架构模式非常熟悉。尽管对于层的数量和类型没有具体限制&#xff0c;但大部分分层架构主要由四层组成&#xff1a;展现层、业务层、持久层和数据库层&#xff0c;如…

Peter算法小课堂—树状数组

大家好&#xff0c;我是人见人爱&#xff0c;花见花开&#xff0c;车见车爆胎的树状数组Peter Pan&#xff0c;hhh 讲正文前&#xff0c;先来一个长文警告⚠很重要的知识点&#xff1a;L SB&#xff08;SB&#xff1f;&#xff09; LSB 怎么算呢&#xff1f; 哦……懂了&…

LeetCode-79. 单词搜索【数组 字符串 回溯 矩阵】

LeetCode-79. 单词搜索【数组 字符串 回溯 矩阵】 题目描述&#xff1a;解题思路一&#xff1a;回溯 回溯三部曲。这里比较关键的是给board做标记&#xff0c;防止之后搜索时重复访问。解题思路二&#xff1a;回溯算法 dfs,直接看代码,很容易理解。visited哈希&#xff0c;防止…

这个世界万物存在只有一种关系:博弈

$上证指数(SH000001)$ 我能给各位最大的帮助可能就是第一个从红警游戏引入了情绪周期视角的概念&#xff0c;而这个概念可以帮助很多人理解市场成为一种可能性&#xff0c;如果不理解可以重新回归游戏进行反复体验&#xff0c;你体验的足够多&#xff0c;思考的足够多&#xff…

力扣日记4.6-【动态规划篇】746. 使用最小花费爬楼梯

力扣日记&#xff1a;【动态规划篇】746. 使用最小花费爬楼梯 日期&#xff1a;2024.4.6 参考&#xff1a;代码随想录、力扣 746. 使用最小花费爬楼梯 题目描述 难度&#xff1a;简单 给你一个整数数组 cost &#xff0c;其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用…

计算机网络——33多点访问协议

多点访问协议 多路访问链路和协议 两种类型的链路&#xff08;一个子网内部链路连接形式&#xff09; 点对点 拨号访问的PPP以太网交换机和主机之间的点对点链路 广播 传统以太网HFC上行链路802.11无线局域网 多路访问协议 单个共享的广播型链路 2个过更多结点同时传送&am…

c# 指数搜索(Exponential Search)

该搜索算法的名称可能会产生误导&#xff0c;因为它的工作时间为 O(Log n)。该名称来自于它搜索元素的方式。 给定一个已排序的数组和要 搜索的元素 x&#xff0c;找到 x 在数组中的位置。 输入&#xff1a;arr[] {10, 20, 40, 45, 55} x 45 输出&#xff1a;在索…

Aurora8b10b(1)IP核介绍并基于IP核进行设计

文章目录 前言一、IP核设置二、基于IP核进行设计2.1、设计框图2.2、aurora_8b10b_0模块2.3、aurora_8b10b_0_CLOCK_MODULE2.4、aurora_8b10b_0_SUPPORT_RESET_LOGIC2.5、aurora8b10b_channel模块2.6、IBUFDS_GTE2模块2.7、aurora_8b10b_0_gt_common_wrapper模块2.8、aurora8b10…

Element UI 消息提示 Message

1. Message 消息提示 本文使用的是 Element UI v2.5.13 Message 常用于主动操作后的反馈提示。比如&#xff1a;用于提交表单后的提示&#xff0c;成功或失败 全局方法 Element 为 Vue.prototype 添加了全局方法 $message&#xff0c;因此可以通过 Vue 实例直接调用 export …

GIS水文分析填充伪洼地学习

1 基本操作 洼地是指流域内被较高高程所包围的局部区域&#xff1b; 分为自然洼地和伪洼地&#xff1b; 自然洼地是自然界实际存在的洼地&#xff1b; 在 DEM 数据中&#xff0c;由于数据处理的误差和不合适的插值方法所产生的洼地&#xff0c;称为伪洼地&#xff1b; DEM 数据…

文件服务器之二:SAMBA服务器

文章目录 什么是SAMBASAMBA的发展历史与名称的由来SAMBA常见的应用 SAMBA服务器基础配置配置共享资源Windows挂载共享Linux挂载共享 什么是SAMBA 下图来自百度百科 SAMBA的发展历史与名称的由来 Samba是一款开源的文件共享软件&#xff0c;它基于SMB&#xff08;Server Messa…

Python-链表常用操作方法

在 Python 中&#xff0c;可以使用类来表示链表节点&#xff0c;然后通过链接节点来构建链表。以下是一些 Python 中链表的常用方法和操作&#xff1a; 定义链表节点类&#xff1a; class ListNode:def __init__(self, val0, nextNone):self.val valself.next next创建链表&a…

秒杀设计思路

目录 1. 系统前端优化 2. 应用层优化 3. 负载均衡 4. 业务层优化 5. 数据库优化 6. 缓存策略 7. 后端优化 8. 安全防护 9. 系统监控和预警 秒杀系统设计需要考虑高并发、高可用、低延迟等因素&#xff0c;以下是一些常见的设计方案&#xff1a; 1. 系统前端优化 静态…

TensorFlow Lite 在安卓开发中的应用及其关键组件研究

摘要 随着移动设备计算能力的增强和人工智能技术的发展&#xff0c;Google 推出的 TensorFlow Lite 成为了在安卓平台上实现本地机器学习模型部署的重要工具。本文旨在全面探讨 TensorFlow Lite 在安卓开发中的角色、优势与局限性&#xff0c;分析其典型应用场景&#xff0c;并…

Python环境搭建—安装PyCharm开发工具

&#x1f947;作者简介&#xff1a;CSDN内容合伙人、新星计划第三季Python赛道Top1 &#x1f525;本文已收录于Python系列专栏&#xff1a; 零基础学Python &#x1f4ac;订阅专栏后可私信博主进入Python学习交流群&#xff0c;进群可领取Python视频教程以及Python相关电子书合…

基于SpringBoot的“网上书城管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“网上书城管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 系统首页界面图 用户注册界面…

传输层 --- TCP (上篇)

目录 1. TCP 1.1. TCP协议段格式 1.2. TCP的两个问题 1.3. 如何理解可靠性 1.4. 理解确认应答机制 2. TCP 报头中字段的分析 2.1. 序号和确认序号 2.1.1. 序号和确认序号的初步认识 2.1.2. 如何正确理解序号和确认序号 2.2. TCP是如何做到全双工的 2.3. 16位窗口大小…