Verilog基础(一):基础元素
verilog基础
我先说,看了肯定会忘,但是重要的是这个过程,我们知道了概念,知道了以后在哪里查询。语法都是术,通用的概念是术。所以如果你有相关的软件编程经验,那么其实开启这个学习之旅,你会感受到熟悉,也会感受到别致。
入门
- 如何开始
欢迎来到二进制的世界,数字逻辑的入门一开始可能有难度,因为你需要学习新的概念,新的硬件描述语言(HDL – Hardware Description Language)例如 verilog
,几个新的仿真软件和一块FPGA的板子.但是这能帮你更加深刻的理解计算机的运作原理.
设计电路需要如下几个步骤:
- 编写HDL(verilog)代码
- 编译代码生成电路
- 模拟电路并修复错误
下面,我们来个简单的例子,请把one
的输出设为1:
- Module Declaration
module top_module(output one);
- Solution
module top_module( output one );assign one = 1;endmodule
- 输出0
建立一个没有输入,输出为常数0的电路.
本系列题使用verilog-2001 ANSI-style 的端口声明语法,因为它更容易阅读并减少了拼写错误.如果愿意,可以使用旧的verilog-1995语法.例如,下面的两个模块声明是可接受的和等效的:
module top_moduel(zero);output zero;//verilog-1995
endmodulemodule top_module(output zero);
//verilog-2001
endmodule
- Module Declaration
module top_module(output zero
);
- Solution
module top_module(output zero
);// Module body starts after semicolonassign zero=0;
endmodule
Verilog 语言
基础元素
- wire类型
创建一个具有一个输入和一个输出的模块,其行为想一条"线"(Wire)。
与物理线不同但十分相似,Verilog中的线(和其他信号)是定向的。
这意味着信息只在一个方向上流动,从(通常是一个)源流向汇点(该源通常也被称为驱动程序,将值驱动到wire上)。
在verilog"连续赋值"(assign left_side=right_side;)中,右侧的信号值被驱动到左侧的"线"上。
请注意:赋值是"连续的"(Continuous Assignments),因为如果右侧的值发生更改,分配也会一直持续,因此左侧的值将随之改变。(这里与其他语言有很大区别)。 连续分配不是一次性事件,其产生的变化是永久的。
想要真正理解为啥会这样,你首先要明白,你并不是在编写程序,你其实是在用代码"画"电路!
因此输入端的电平高低的变化必然会影响到wire的另一端,你可以想像真的有一根电线连接两个变量。
模块(module)上的端口(port)也有一个方向(通常是输入 – input或输出 – output)。
输入端口由来自模块外部的东西驱动,而输出端口驱动外部的东西。从模块内部查看时,输入端口是驱动程序或源,而输出端口是接收器。
下图说明了电路的每个部分如何对应Verilog代码的每个部分。
- 模块和端口声明创建电路的黑色部分。
- 您的任务是通过添加一个assign语句来创建一条线(绿色)。
- 盒子外的部件不是您的问题,但您应该知道,通过将测试激励连接到top_module上的端口来测试电路。
除了连续赋值之外,Verilog还有另外三种用于程序块(Procedural block)的赋值类型,其中两种是可综合的。在开始使用Procedural block之前,我们不会使用它们.
- Module Declaraction
module top_module( input in, output out );
- Solution
module top_module( input in, output out );assign out = in;
endmodule
这里的 Module Declaraction 和 Solution就像是对应C里面的声明和定义实现
- Four wires
创建一个具有3个输入和4个输出的模块,这些输入和输出的行为如下:
A ->W
B -> X
B -> Y
C -> Z
下图说明了电路的每个部分如何对应Verilog代码的每个部分.模块外部有三个输入端口和四个输出端口.
当您有多个assign语句时,它们在代码中的出现顺序并不重要.与编程语言不同,assign语句(“连续赋值”)描述事物之间的连接,而不是将值从一个事物复制到另一个事物的操作.
可能现在应该澄清的一个潜在的困惑来源是:这里的绿色箭头表示电线之间的连接,但不是wire本身.
模块本身已经声明了7条线(名为A、B、C、W、X、Y和Z).这是因为input与output被声明为了wire类型.因此,assign语句不会创建wire,而是描述了在已存在的7条线之间创建的连接.
- Module Declaraction
module top_module(input a,b,c;output w,x,y,z
);
- Solution
module top_module( input a,b,c,output w,x,y,z );assign w=a;assign x=b;assign y=b;assign z=c;
endmodule
- 反转器 (Inveter)
创建实现非门的模块.
这个电路和电线相似,但有点不同.当把电线从进线连接到出线时,我们要实现一个反相器(非门),而不是一根普通的线.
使用assign语句.assign语句将连续地将in取反并输出.
- Module
module top_module( input in, output out );
- Solution
module top_module( input in, output out );assign out = !in;
endmodule
- 与门 (AND gate)
创建实现和门的模块.
这个电路现在有三条线(A、B和OUT).导线A和B已经具有由输入端口驱动的值.但目前的布线并不是由任何东西驱动的.写一个赋值语句,用信号A和B的和来驱动.
输入线由模块外部的东西驱动.assign语句将把一个逻辑级别驱动信号连接到一条线上.正如您可能期望的那样,一条线不能有多个驱动信号(如果有的话,它的逻辑级别是什么?),并且没有驱动信号的导线将具有未定义的值(在合成硬件时通常被视为0,但有时候会出现奇怪的错误).
- Module Declaraction
module top_module( input a, input b, output out );
- Solution
module top_module( input a, input b, output out );
assign out = a&b;
endmodule
- 或非门 (NOR gate)
创建实现或非门的模块.或非门是一个输出反转的或门.
assign语句用一个值来驱动(drive)一条线(或者更正式地称为"net").这个值可以是任意复杂的函数,只要它是一个组合逻辑(即,无内存(memory-less),无隐藏状态).
- Module Declaraction
module top_module( input a, input b, output out );
- Solution
module top_module( input a, input b, output out );assign out = !(a|b);
endmodule
- 异或非门 (XNOR gate)
实现异或非门模块.
- Module Declaraction
module top_module( input a, input b, output out );
- Solution
module top_module( input a, input b, output out );assign out = !(a^b);
endmodule
- 声明wires
到目前为止,电路都十分简单。随着电路变得越来越复杂,您将需要wire将内部组件连接在一起。当您需要使用导线时,您应该在模块体中在首次使用之前的某个地方声明它.
(将来,您将遇到更多类型的信号和变量,它们也以相同的方式声明,但现在,我们将从Wire类型的信号开始).
module top_module (input in, // Declare an input wire named "in"output out // Declare an output wire named "out"
);wire not_in; // Declare a wire named "not_in"assign out = ~not_in; // Assign a value to out (create a NOT gate).assign not_in = ~in; // Assign a value to not_in (create another NOT gate).endmodule // End of module "top_module"
实现以下电路.
创建两个wire(命名任意)以将and/or gate 连接在一起.
请注意,Not gate 是输出,因此您不必在这里声明第三条线.
wire可有多个输出,但只能有一个输入驱动. 下面这例子:
如果您遵循图中的电路结构,那么应该以四个赋值语句结束,因为有四个信号需要赋值.
- Module Declaraction
`default_nettype none
module top_module(input a,input b,input c,input d,output out,output out_n );
- Solution
`default_nettype none
module top_module(input a,input b,input c,input d,output out,output out_n ); wire inside1,inside2;assign inside1 = a&b;assign inside2 = c&d; assign out = inside1|inside2;assign out_n = !(out);endmodule
- 7458模块
实现如下电路:
- Module Declaraction
module top_module ( input p1a, p1b, p1c, p1d, p1e, p1f,output p1y,input p2a, p2b, p2c, p2d,output p2y );
- Solution
module top_module ( input p1a, p1b, p1c, p1d, p1e, p1f,output p1y,input p2a, p2b, p2c, p2d,output p2y );wire inside1,inside2,inside3,inside4;assign inside1 = p1a&p1b&p1c;assign inside2 = p1d&p1e&p1f;assign inside3 = p2a&p2b;assign inside4 = p2c&p2d;assign p1y = inside1|inside2;assign p2y = inside3|inside4;endmodule
容器(Vectors)
- 容器介绍
vector被用来对相关的信号进行分组,以便于操作.例如,Wire[7:0]w
;
声明一个名为w 的 8 位数组,在功能上相当于具有8条独立的线.
请注意,vector的声明将维度(dimensions 即数组长度)放在容器名称之前,这与C语法相比不常见.
至于为什么会是如下声明,主要是采用了小端序.
Wire[99:0]my_vector;//声明一个长度为100容器
assign out=my_vector[10];//从数组中选择一位
构建一个具有一个3位vector输入的电路,并将其拆分为三个单独的1位输出.
- Module Declaraction
module top_module ( input wire [2:0] vec,output wire [2:0] outv,output wire o2,output wire o1,output wire o0 );
- Solution
module top_module ( input wire [2:0] vec,output wire [2:0] outv,output wire o2,output wire o1,output wire o0 ); // Module body starts after module declarationassign o0 = vec[0];assign o1 = vec[1];assign o2 = vec[2];assign outv = vec;
endmodule
- 容器细节
vector声明如下:
type [upper:lower] vector_name;
type
指定了vector的类型,通常是wire
或者reg
.
wire [2:0] a, c; // Two vectors
assign a = 3'b101; // a = 101
assign b = a; // b = 1 implicitly-created wire
assign c = b; // c = 001 <-- bug
my_module i1 (d,e); // d and e are implicitly one-bit wide if not declared.// This could be a bug if the port was intended to be a vector.
这里有一个问题:变量b在之前并没有被声明。在Verilog中,如果在使用一个变量之前没有声明它,编译器可能会隐式地声明它,但具体行为依赖于编译器的实现和设置。对于assign语句中的未声明变量,Verilog标准并没有规定必须隐式声明为多少位宽。如果编译器隐式地将b声明为一个单一位宽的线网(这是某些编译器的默认行为),那么这里就会发生位宽不匹配的问题。正确的做法是显式声明b的位宽,例如wire [2:0] b;。
由于b可能没有被正确声明为3位宽(如上所述),这里将b的值赋给c可能不会产生预期的结果。如果b被隐式声明为1位宽,那么即使a是101,b也只能存储最低位(1),然后这个值会被扩展到c的3位宽(变成001),这不是原意。
这行代码实例化了一个名为my_module的模块,其实例名为i1。d和e是连接到my_module端口的信号。如果d和e在之前没有被声明,并且my_module的对应端口是向量而不是单一位,那么这里也可能存在位宽不匹配的问题。在Verilog中,如果端口连接时未声明的信号会被隐式声明为1位宽。为了避免潜在的错误,应该显式声明所有端口信号的位宽。
- 关于"片选"(Part Selection)
访问整个数组只需要:
assign w = a;
而访问数组的一部分,若长度在赋值时不匹配,则用0补齐例如:
reg [7:0] c;
assign c = x[3:1];
//此时,长度不匹配,则用0补齐w[3:0] // Only the lower 4 bits of w
x[1] // The lowest bit of x
x[1:1] // ...also the lowest bit of x
z[-1:-2] // Two lowest bits of z
b[3:0] // Illegal. Vector part-select must match the direction of the declaration.
b[0:3] // The *upper* 4 bits of b.
assign w[3:0] = b[0:3]; // Assign upper 4 bits of b to lower 4 bits of w. w[3]=b[0], w[2]=b[1], etc.
建立一个电路,将一个半字(16 bits,[15:0])分成高8位[15:8],与低8位[7:0]输出.
- Module Declaraction
`default_nettype none // Disable implicit nets. Reduces some types of bugs.
module top_module( input wire [15:0] in,output wire [7:0] out_hi,output wire [7:0] out_lo );
- Solution
`default_nettype none // Disable implicit nets. Reduces some types of bugs.
module top_module( input wire [15:0] in,output wire [7:0] out_hi,output wire [7:0] out_lo );assign out_lo = in[7:0];assign out_hi = in[15:8];
endmodule
在Verilog中,default_nettype 指令用于指定当在代码中遇到未声明的信号时,这些信号应该被隐式地声明为什么类型的线网(net)。默认情况下,如果不指定 default_nettype,某些Verilog编译器可能会将未声明的信号隐式地声明为1位宽的 wire 类型。 然而,这种行为可能会导致难以追踪的bug,特别是当期望的信号宽度与实际隐式声明的宽度不匹配时。
指令 default_nettype none 的作用是禁用隐式线网的声明。这意味着,如果在代码中使用了未声明的信号,编译器将会报错,而不是隐式地为其创建一个线网。这有助于减少由于未声明信号而导致的某些类型的bug,因为它迫使设计师显式地声明所有使用的信号及其位宽。
- 容器的片选(Vector part select)
32位矢量可以被视为包含4个字节(位[31:24]、[23:16]等).建立一个电路,使4字节字颠倒顺序.
aaaaaaaabbbbbbcccccccccddddddd=>ddddddddccccccccccbbbbbbbaaaaaaaa
此操作通常在需要交换一段数据的结束地址时使用,例如在Little Endian(小端序) x86系统和许多Internet协议中使用的Big Endian(大端序格式之间.
- Module Declaraction
module top_module( input [31:0] in,output [31:0] out );
- Solution
module top_module( input [31:0] in,output [31:0] out );//// assign out[31:24] = ...;assign out[31:24] = in[7:0];assign out[23:16] = in[15:8];assign out[15:8] = in[23:16];assign out[7:0] = in[31:24];
endmodule
- 位级操作(Bitwise operators)
建立一个电路,该电路有两个3-bits输入,用于计算两个vector的"基于位"的或(bitwise-OR)、两个矢量的"逻辑或"(Logical-OR)和两个矢量的非(NOT).将b的非放在out-not的高位部分(即[5:3]),将a的非放在低位部分.
看看模拟波形,看看bitwise-OR与Logical-OR的区别.
- Module Declaraction
module top_module( input [2:0] a,input [2:0] b,output [2:0] out_or_bitwise,output out_or_logical,output [5:0] out_not
);
- Solution
module top_module(input [2:0] a, input [2:0] b, output [2:0] out_or_bitwise,output out_or_logical,output [5:0] out_not
);assign out_or_bitwise = a | b;assign out_or_logical = a || b;assign out_not[2:0] = ~a; // Part-select on left side is o.assign out_not[5:3] = ~b; //Assigning to [5:3] does not conflict with [2:0]endmodule
- 4位Vecotr
建立一个具有4为输入的组合电路,输出要求如下:
-
out_and
: 输入经过 “与门” 后的结果 -
out_or
: 输入经过 “或门” 后的结果 -
out_xor
: 输入经过 “异或门” 后的结果 -
Module Declaraction
module top_module( input [3:0] in,output out_and,output out_or,output out_xor
);
- Solution
module top_module( input [3:0] in,output out_and,output out_or,output out_xor
);assign out_and = in[0]&in[1]&in[2]&in[3];assign out_or = in[0]|in[1]|in[2]|in[3];assign out_xor = in[0]^in[1]^in[2]^in[3];
endmodule
- Vector连接操作符(Vector concatenation operator)
片选用于选择vector的部分。连接运算符{a,b,c}用于通过将vector的较小部分连接在一起来创建较大的vector.
{3'b111, 3'b000} => 6'b111000
{1'b1, 1'b0, 3'b101} => 5'b10101
{4'ha, 4'd10} => 8'b10101010 // 4'ha and 4'd10 are both 4'b1010 in binary
连接需要知道每个组件的宽度,因此,{1,2,3}是非法的,并导致错误消息:串联中不允许使用未经大小化的常量.
连接操作符可以在赋值的左侧和右侧使用.
input [15:0] in;
output [23:0] out;
assign {out[7:0], out[15:8]} = in; // Swap two bytes. Right side and left side are both 16-bit vectors.
assign out[15:0] = {in[7:0], in[15:8]}; // This is the same thing.
assign out = {in[7:0], in[15:8]}; // This is different. The 16-bit vector on the right is extended to// match the 24-bit vector on the left, so out[23:16] are zero.// In the first two examples, out[23:16] are not assigned.
连接并重新分割给定输入:
- Module Declaraction
module top_module (input [4:0] a, b, c, d, e, f,output [7:0] w, x, y, z );
- Solution
module top_module (input [4:0] a, b, c, d, e, f,output [7:0] w, x, y, z );//// assign { ... } = { ... };assign {w[7:0],x[7:0],y[7:0],z[7:0]} = {a[4:0],b[4:0],c[4:0],d[4:0],e[4:0],f[4:0],2'b11};
endmodule
- 反转Vector
反转一个8位vector
- Module Declaraction
module top_module( input [7:0] in,output [7:0] out
);
- Solution
module top_module( input [7:0] in,output [7:0] out
);assign {out[0],out[1],out[2],out[3],out[4],out[5],out[6],out[7]} = in;
endmodule
- 拷贝操作符(Replication operator)
连接运算符允许将vector连接在一起以形成较大的vector.但是有时候你想把同一个东西连接在一起很多次,比如assign A = {B, B, B, B, B, B};
这样的事情仍然很乏味.复制运算符允许复制vector并将它们连接在一起:
{num{vector}}
这会将vector
复制num
次.
例如:
{5{1'b1}} // 5'b11111 (or 5'd31 or 5'h1f)
{2{a,b,c}} // The same as {a,b,c,a,b,c}
{3'd5, {2{3'd6}}} // 9'b101_110_110. It's a concatenation of 101 with// the second vector, which is two copies of 3'b110.
复制运算经常会用在"有符号数"的扩转运算中,假如将一个8位有符号数扩展到16位,我们需要将其符号位进行复制并填充到扩展位.即:
8'b10000001 => 16'b1111111110000001
//这就是有符号数的扩展
- Module Declaraction
module top_module (input [7:0] in,output [31:0] out );
- Solution
module top_module (input [7:0] in,output [31:0] out );//// assign out = { replicate-sign-bit , the-input };assign out[31:0] = {{24{in[7]}},in[7:0]};
endmodule
- 拷贝练习
给定5个1位的输入信号,并进行如下图的比较运算,相同的位记为1,并储存在out中.
out[24] = ~a ^ a; // a == a, so out[24] is always 1.
out[23] = ~a ^ b;
out[22] = ~a ^ c;
...
out[ 1] = ~e ^ d;
out[ 0] = ~e ^ e;
- Module Declaraction
module top_module (input a, b, c, d, e,output [24:0] out );
- Solution
module top_module (input a, b, c, d, e,output [24:0] out );//// The output is XNOR of two vectors created by // concatenating and replicating the five inputs.// assign out = ~{ ... } ^ { ... };assign out = ~{{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}} ^ {5{a,b,c,d,e}};
endmodule
相关文章:
Verilog基础(一):基础元素
verilog基础 我先说,看了肯定会忘,但是重要的是这个过程,我们知道了概念,知道了以后在哪里查询。语法都是术,通用的概念是术。所以如果你有相关的软件编程经验,那么其实开启这个学习之旅,你会感…...
Games104——游戏引擎Gameplay玩法系统:基础AI
这里写目录标题 寻路/导航系统NavigationWalkable AreaWaypoint NetworkGridNavigation Mesh(寻路网格)Sparse Voxel Octree Path FindingDijkstra Algorithm迪杰斯特拉算法A Star(A*算法) Path Smoothing Steering系统Crowd Simu…...
vue生命周期及其作用
vue生命周期及其作用 1. 生命周期总览 2. beforeCreate 我们在new Vue()时,初始化一个Vue空的实例对象,此时对象身上只有默认的声明周期函数和事件,此时data,methods都未被初始化 3. created 此时,已经完成数据观测࿰…...
数据分析师使用Kutools for Excel 插件
数据分析师使用Kutools for Excel 插件 Kutools for Excel 是一款功能强大的 Excel 插件,旨在提高 Excel 用户的工作效率,简化复杂的操作。它提供了超过 300 个增强功能,帮助用户快速完成数据管理、格式化、排序、分析等任务,特别…...
毫秒级响应的VoIP中的系统组合推荐
在高并发、低延迟、毫秒级响应的 VoIP 场景中,选择合适的操作系统组合至关重要。以下是针对 Ubuntu linux-lowlatency、CentOS Stream kernel-rt 和 Debian 自定义 PREEMPT_RT 的详细对比及推荐: 1. 系统组合对比 特性Ubuntu linux-lowlatencyCentO…...
unordered_map/set的哈希封装
【C笔记】unordered_map/set的哈希封装 🔥个人主页:大白的编程日记 🔥专栏:C笔记 文章目录 【C笔记】unordered_map/set的哈希封装前言一. 源码及框架分析二.迭代器三.operator[]四.使用哈希表封装unordered_map/set后言 前言 哈…...
表格标签的使用
一.表格标签 1.1表格标签的作用 用来显示和展示数据,不是用来布局页面的。 1.2表格的基本语法 <table> //用于定义表格标签 <tr> // table row 用于定义表格中的行,必须嵌套在<table> </table>标签中 <td>单元格内的文…...
python算法和数据结构刷题[5]:动态规划
动态规划(Dynamic Programming, DP)是一种算法思想,用于解决具有最优子结构的问题。它通过将大问题分解为小问题,并找到这些小问题的最优解,从而得到整个问题的最优解。动态规划与分治法相似,但区别在于动态…...
【cocos creator】【模拟经营】餐厅经营demo
下载:【cocos creator】模拟经营餐厅经营...
编程AI深度实战:给vim装上AI
系列文章: 编程AI深度实战:私有模型deep seek r1,必会ollama-CSDN博客 编程AI深度实战:自己的AI,必会LangChain-CSDN博客 编程AI深度实战:给vim装上AI-CSDN博客 编程AI深度实战:火的编程AI&…...
信息学奥赛一本通 2088:【22CSPJ普及组】逻辑表达式(expr) | 洛谷 P8815 [CSP-J 2022] 逻辑表达式
【题目链接】 ybt 2088:【22CSPJ普及组】逻辑表达式(expr) 洛谷 P8815 [CSP-J 2022] 逻辑表达式 【题目考点】 1. 表达式树:中缀表达式建树 可以看该问题信息学奥赛一本通 1356:计算(calc) 了解中缀表达式建树过程。 【解题思路】 解法…...
Linux系统管理
文章目录 一、进程与服务二、systemctl基本语法操作 三、系统运行级别Linux进程运行级别查看当前运行级别修改当前运行级别 四、关机重启命令 一、进程与服务 守护进程与服务是一个东西。 二、systemctl 基本语法 systemctl start|stop|restart|status 服务名查看服务的方法…...
CTFSHOW-WEB入门-命令执行71-77
题目:web 71 题目:解题思路:分析可知highlight_file() 函数被禁了,先想办法看看根目录:cvar_export(scandir(dirname(‘/’))); 尝试一下发现很惊奇:(全是?)这种情况我也…...
[MRCTF2020]Ez_bypass1(md5绕过)
[MRCTF2020]Ez_bypass1(md5绕过) 这道题就是要绕过md5强类型比较,但是本身又不相等: md5无法处理数组,如果传入的是数组进行md5加密,会直接放回NULL,两个NuLL相比较会等于true; 所以?id[]1&gg…...
PPT演示设置:插入音频同步切换播放时长计算
PPT中插入音频&同步切换&放时长计算 一、 插入音频及音频设置二、设置页面切换和音频同步三、播放时长计算四、使用宏设置设置页面切换和音频同步一、 插入音频及音频设置 1.插入音频:点击菜单栏插入-音频-选择PC上的音频(已存在的音频)或者录制音频(现场录制) …...
Modbus Slave RTU 在 AVP28335(兼容德州仪器TMS 320 28335) 上实现含源码及注释。
今天先把题目先给出来, 在近两天会把源码 (含详细注释 )及部署、测试结果给出来, 希望能给大家帮助。(原来这个程序在CSDN中,有小伙伴已经写了一些,但是发现里面埋了很多坑,例如&…...
git-secret 使用教程
以下是一份详细的 git-secret 使用教程,包含常见场景的 Bash 代码示例: 1. 安装 git-secret # Ubuntu/Debian sudo apt-get install git-secret# macOS (Homebrew) brew install git-secret# 其他 Linux (Snap) sudo snap install git-secret# 验证安装…...
防火墙安全策略
目录 一.拓扑及需求 二.需求分析 三.配置详细信息 防火墙: OA server: Web Server: PC1: 编辑PC2: PC3: 配置安全区域: 交换机: 四.需求实现以及测试: 1.…...
蓝桥杯python基础算法(2-2)——基础算法(D)——进制转换*
目录 五、进制转换 十进制转任意进制,任意进制转十进制 例题 P1230 进制转换 作业 P2095 进制转化 作业 P2489 进制 五、进制转换 十进制转任意进制,任意进制转十进制 int_to_char "0123456789ABCDEF" def Ten_to_K(k, x):answer "…...
VSCode源码分析参考资料
VSCode Architecture Analysis - Electron Project Cross-Platform Best Practices 中文版 VSCode 架构分析 - Electron 项目跨平台最佳实践 Sihan Li博客上的vscode源码分析系列:分析了微服务架构、事件体系、资源管理、配置系统等 文召博客上的vscode 源码解析…...
深入理解 Rust 模块中的路径与公开性:绝对路径、相对路径和 `pub` 的应用
1. 路径的两种形式:绝对路径与相对路径 在 Rust 中,路径类似于文件系统中的目录路径,用来告诉编译器去哪里查找某个项。路径主要有两种形式: 绝对路径 绝对路径从 crate 的根开始。对于当前 crate 的代码,绝对路径以关…...
DeepSeek R1 大模型本地部署指南
以下是部署DeepSeek R1大模型的详细Markdown指南,可直接保存为.md文件并分享: # DeepSeek R1 大模型本地部署指南**适用系统**:Windows 10/11 & Linux (Ubuntu 20.04)---## 目录 1. [硬件要求](#硬件要求) 2. [准备工作](#准备工作) 3. […...
从Proxmox VE开始:安装与配置指南
前言 Proxmox Virtual Environment (Proxmox VE) 是一个开源的虚拟化平台,基于Debian Linux,支持KVM虚拟机和LXC容器。它提供了一个强大的Web管理界面,方便用户管理虚拟机、存储、网络等资源。Proxmox VE广泛应用于企业级虚拟化、云计算和开…...
Docker 安装详细教程(适用于CentOS 7 系统)
目录 步骤如下: 1. 卸载旧版 Docker 2. 配置 Docker 的 YUM 仓库 3. 安装 Docker 4. 启动 Docker 并验证安装 5. 配置 Docker 镜像加速 总结 前言 Docker 分为 CE 和 EE 两大版本。CE即社区版(免费,支持周期7个月)…...
前端 | 浅拷贝深拷贝
在前端开发中,我们经常需要复制对象或数组,但不同的复制方式可能会影响数据的完整性和应用的稳定性。本文将深入探讨浅拷贝(Shallow Copy)和深拷贝(Deep Copy)的区别、实现方式及适用场景。 1. 浅拷贝 1.…...
巧用 Cursor+Coze,轻松简化小程序开发
一、为啥要用 Cursor+Coze 简化小程序开发 家人们,如今小程序简直火出圈啦!不管你是电商从业者,还是服务行业的工作者,又或是自媒体运营者,拥有一个小程序,就相当于给业务插上了腾飞的翅膀,能带来更多的流量和机会。但是,小程序开发的过程,那可真是充满了挑战。从最开…...
Spring Boot常用注解深度解析:从入门到精通
今天,这篇文章带你将深入理解Spring Boot中30常用注解,通过代码示例和关系图,帮助你彻底掌握Spring核心注解的使用场景和内在联系。 一、启动类与核心注解 1.1 SpringBootApplication 组合注解: SpringBootApplication Confi…...
解决Mac安装软件的“已损坏,无法打开。 您应该将它移到废纸篓”问题
mac安装软件时,如果出现这个问题,其实很简单 首先打开终端,输入下面的命令 sudo xattr -r -d com.apple.quarantine 输入完成后,先不要回车,点击访达--应用程序--找到你无法打开的app图标,拖到终端窗口中…...
爱普生L3153打印机无线连接配置流程
家里使用的是移动宽带中兴路由器,有WPS功能,进入192.168.1.1管理员页面,用户名user,密码在路由器背面(可以登录后修改密码)。在网络-WLAN网络配置-WPS中,点击push button,激活路由器…...
第二十章 存储函数
目录 一、概述 二、语法 三、示例 一、概述 前面章节中,我们详细讲解了MySQL中的存储过程,掌握了存储过程之后,学习存储函数则肥仓简单,存储函数其实是一种特殊的存储过程,也就是有返回值的存储过程。存储函数的参数…...
pytorch实现门控循环单元 (GRU)
人工智能例子汇总:AI常见的算法和例子-CSDN博客 特性GRULSTM计算效率更快,参数更少相对较慢,参数更多结构复杂度只有两个门(更新门和重置门)三个门(输入门、遗忘门、输出门)处理长时依赖一般适…...
unity报错不存在类型或者命名空间
导入资源或者打开项目时,突然发现多了一堆报错,如 Assets\2DGamekit\Utilities\DefaultPlayables\ScreenFader\ScreenFaderBehaviour.cs(5,19): error CS0234: The type or namespace name UI does not exist in the namespace UnityEngine (are you mi…...
Qt展厅播放器/多媒体播放器/中控播放器/帧同步播放器/硬解播放器/监控播放器
一、前言说明 音视频开发除了应用在安防监控、视频网站、各种流媒体app开发之外,还有一个小众的市场,那就是多媒体展厅场景,这个场景目前处于垄断地位的软件是HirenderS3,做的非常早而且非常全面,都是通用的需求&…...
Spring Bean 的生命周期介绍
Spring Bean 的生命周期涉及多个阶段,从实例化到销毁,在开发中我们可以通过各种接口和注解介入这些阶段来定制化自己的功能。以下是详细的生命周期流程: 1. Bean 的实例化(Instantiation) 方式:通过构造函…...
奥卡姆剃刀原理:用简单的力量,解锁复杂的世界
奥卡姆剃刀原理 大名鼎鼎的奥卡姆剃刀原理(Occam’s Razor),其含义很简单,就一句话:“如无必要,勿增实体”。 这句看似简单却蕴含着深刻智慧的话,是由14世纪的英格兰逻辑学家、圣方济各会修士…...
STM32 串口发送与接收
接线图 代码配置 根据上一章发送的代码配置,在GPIO配置的基础上需要再配置PA10引脚做RX接收,引脚模式可以选择浮空输入或者上拉输入,在USART配置串口模式里加上RX模式。 配置中断 //配置中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE…...
如何生成强密码:提高网络安全性的全面指南
引言 在数字化时代,密码的安全性至关重要。随着我们在社交媒体、电子邮件、在线银行等平台上储存越来越多的个人信息,强密码的使用变得更加关键。强密码能有效防止暴力破解、字典攻击等安全威胁。因此,在本文中,我们将深入探讨如…...
如何不更新application.yml而更新spring的配置
更改应用程序外部属性的位置 默认情况下,来自不同来源的属性会按定义的顺序添加到 Spring 中(有关确切顺序,请参阅“Spring Boot 功能”部分中的“外部化配置”)。Environment 您还可以提供以下系统属性(或环境变量&…...
【Unity踩坑】Unity项目管理员权限问题(Unity is running as administrator )
问题描述: 使用Unity Hub打开或新建项目时会有下面的提示。 解决方法: 打开“本地安全策略”: 在Windows搜索栏中输入secpol.msc并回车,或者从“运行”对话框(Win R,然后输入secpol.msc)启…...
【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter1-什么是 JavaScript
一、什么是 JavaScript 虽然 JavaScript 和 ECMAScript(发音为“ek-ma-script”) 基本上是同义词,但 JavaScript 远远不限于 ECMA-262 所定义的那样。没错,完整的 JavaScript 实现包含以下几个部分。 核心(ECMAScript&…...
队列 + 宽搜(4题)
目录 1.n叉树的层序遍历 2.二叉树的锯齿形层序遍历 3.二叉树的最大宽度 4.在每个树行中找最大值 1.n叉树的层序遍历 429. N 叉树的层序遍历 - 力扣(LeetCode) 我们只需要把某个节点出队的时候把它的孩子节点添加进来即可。 出队的次数就是最开始队列…...
二、面向对象
一、结构体类型 结构体类型是一种自定义类型,用于创建我们游戏或者实际业务中的自定义类型. 代码中变量有通用的,可以使用结构体,包裹起来。 1、成员变量 /// <summary> /// 英雄结构体 /// </summary> struct Hero {//成员p…...
【DeepSeek背后的技术】系列二:大模型知识蒸馏(Knowledge Distillation)
目录 1 引言2 操作步骤和公式说明2.1 准备教师模型(Teacher Model)和学生模型(Student Model)2.2 生成软标签(Soft Labels)2.3 定义蒸馏损失函数2.4 训练学生模型2.5 调整超参数2.6 评估与部署 3 其他知识蒸…...
PyQt4学习笔记2】QMainWindow
目录 一、创建 QMainWindow 组件 1. 创建工具栏 2. 创建停靠窗口 3. 设置状态栏 4. 设置中央窗口部件 二、QMainWindow 的主要方法 1. addToolBar() 2. addDockWidget() 3. setStatusBar() 4. setCentralWidget() 5. menuBar() 6. saveState() 和 restoreState() 三、QMainWind…...
《海丰县蔡氏简介》前言
《海丰县蔡氏简介》前言 蔡惠进主编 汕尾市海陆丰蔡姓祖先基本是福建人, 在宋朝时迁至海丰, 因受潮汕文化、 客家文化、 广府文化、 政治归属等系列因素影响, 形成了闽南人一 种新的文化, 既有传统的闽南文化, 又有潮汕…...
深入探索Vue 3组合式API
深入探索Vue 3组合式API 深入探索Vue 3组合式API一、组合式API诞生背景1.1 Options API的局限性1.2 设计目标二、核心概念解析2.1 setup() 函数:组合式API的基石2.2 响应式系统:重新定义数据驱动2.3 生命周期:全新的接入方式2.4 响应式原理探…...
获取 ARM Cortex - M 系列处理器中 PRIMASK 寄存器的值
第一种实现(纯汇编形式) __ASM uint32_t __get_PRIMASK(void) {mrs r0, primaskbx lr }代码分析 __ASM 关键字:这通常是特定编译器(如 ARM GCC 等)用于嵌入汇编代码的指示符。它告诉编译器下面的代码是汇编代码。mrs …...
使用deepseek写一个单击,双击和长按的检测函数
DeepSeek好火,注册试用一下,感觉和chatgpt o1差别不大,唯一的问题就是追多几次就崩溃了,再问不下去了。以下是测试结果。 提问: 请使用c语言写一个函数,输入参数是是为: A为当前的输入量&am…...
MySQL面经
1.范式 第一范式:每一列都不能再拆分 第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不是主键的一部分 第三范式:在第二范式的基础上,非主键列只依赖于主键列,而不依赖于其他非主键…...
【C++】P1765 手机
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯问题描述题目内容示例: 键盘布局 💯我的做法思路问题与优化我的代码实现分析与问题 💯老师的做法思路老师的代码实现分析优点 …...