ASIC-WORLD Verilog(1)一日Verilog
写在前面
在自己准备写一些简单的verilog教程之前,参考了许多资料----asic-world网站的这套verilog教程即是其一。这套教程写得极好,奈何没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。
这是网站原文:Verilog Tutorial
介绍
Verilog 是一种硬件描述语言 (HARDWARE DESCRIPTION LANGUAGE ,HDL)。硬件描述语言是一种用于描述数字系统(例如网络交换机、微处理器或存储器或简单的触发器)的语言。这意味着你可以通过使用 HDL来描述任何级别的任何(数字)硬件。
//D触发器
module d_ff ( d, clk, q, q_bar);input d ,clk;
output q, q_bar;
wire d ,clk;
reg q, q_bar;always @(posedge clk) beginq <= d;q_bar <= ! d;
endendmodule
通过硬件描述语言,你可以描述一个如上图所示的简单D触发器,也可以描述一个超过100 万个逻辑门的复杂设计。Verilog 是业界可用于硬件设计的 HDL 语言之一。它允许我们在行为级(Behavior Level)、寄存器传输级 (Register Transfer Level,RTL)、门级(Gate level)和开关级(switch level)进行数字设计。Verilog 允许硬件设计人员使用行为结构来表达他们的设计,将实现细节推迟到最终设计的后期阶段。
很多想学这门语言的工程师,经常会问这样一个问题:"学Verilog需要多少时间?" 对此我的答案是“如果你碰巧知道至少一种编程语言的话(比如C、Java等),那可能只需要一周的时间。”
设计风格
Verilog 与任何其他硬件描述语言一样,允许采用自下而上(Bottom-up)或自上而下(Top-down)的方法进行设计。
自下而上的设计
传统的电子设计方法是自下而上的,每个设计都是使用标准门电路在门级实现的。随着新设计变得越来越复杂,这种方法几乎无法维护。新系统由 ASIC 或微处理器组成,复杂性达到了数千个晶体管级别。这种传统的自下而上的方法必须让位于新的结构化、层次化的设计方法。没有这些新方法,就无法解决新设计的复杂性。
自上而下的设计
所有设计师都期望的设计风格是自上而下的。真正的自上向下设计允许早期测试、不同技术的轻松更改、结构化系统设计并能提供许多其他优势。但是要实现纯粹的自上而下的设计是非常困难的,基于这个事实,大多数设计都是这两种方法(自下而上和自上而下)的混合,以结合两种方法的优点。
下图展示了自上而下的设计方法。
Verilog的抽象层级
Verilog 支持在不同的抽象层级上进行设计。其中三个非常重要:
- 行为级(Behavioral level)
- 寄存器转换级(Register-Transfer Level)
- 门级(Gate Level)
行为级
通过并行算法(行为)来描述系统。每个算法本身都是有顺序的,这意味着它由一组依次执行的指令组成。函数(Functions)、任务(Tasks)和 Always 块(Always blocks)是主要元素。行为级不考虑设计的结构实现。
寄存器转换级(RTL)
使用寄存器传输级别的设计通过操作和寄存器之间的数据传输来指定电路的特性。这需要使用显式的时钟信号。RTL 设计包含精确的时序边界:操作被安排在特定的时间发生。现代 RTL 代码定义是“任何可综合的代码都称为 RTL 代码”。
门级
在逻辑层内,系统的特性由逻辑链路及其时序属性描述。所有的信号都是离散信号,它们只能是明确的逻辑值('0'、'1'、'X'、'Z')。可用的操作是预定义的逻辑原语(AND、OR、NOT 等门)。对于任何级别的逻辑设计来说,使用门级建模可能都不是一个好主意。门级代码由综合工具等工具生成,此网表一般用于门级仿真和后端。
再介绍
每一个初学者的梦想都是能在一天之内掌握Verilog,至少也要能使用它。为了帮助初学者实现这个梦想,我接下来将讲解一些理论、示例和练习。
本教程不会教您如何编程(软件编程),因为它是为那些有一定编程(软件编程)经验的人设计的。Verilog 并发执行不同的代码块----尽管这与大多数软件编程语言的顺序执行所相反,但二者之间仍有许多相似之处。
此外,一些数字电路的设计背景也对学习Verilog很有帮助。
Verilog 出现之前的设计主要依赖原理图。每个设计,无论复杂程度如何,都是通过原理图设计的。它们难以验证且容易出错,这就很容易形成设计、验证、设计、验证……的漫长且乏味的开发迭代过程。
当 Verilog 出现后,我们突然有了一种新的思考方式来认识逻辑电路。Verilog 设计周期更像是一个传统的编程周期,本教程将引导您完成它。
使用Verilog进行设计的流程是这样的:
- 规格 (Specifications,specs)
- 高层级设计(High level design)
- 低层级设计(Low level (micro) design)
- RTL编码(RTL coding)
- 验证(Verification)
- 综合(Synthesis)
列表中的第一个是规格----我们将对设计施加何种限制和要求?我们要构建什么?
在本教程中,我们将构建一个2路仲裁器(2 agent arbiter):一种在2个源之间进行选择以争夺控制权(mastership)的设备。以下是我们可能会编写的一些规格。
- 2路仲裁器
- 高电平有效的异步复位
- 源 0 优先于源1的固定优先级
- 只要请求被断言,授权就会被断言(意思就是只要输入有效,输出就有效)
一旦我们有了规格,就可以绘制框图了,它基本上算是系统内数据流的一种抽象(什么进入黑盒子?或什么从黑盒子出来?)。我们举的例子很简单,对应的框图如下所示。现在我们还不用担心神奇的黑盒子里有什么。
仲裁器框图
如果现在我们不用Verilog来设计这个仲裁器,标准程序将要求我们绘制一个状态机,然后我们将为每个触发器制作一个包含状态转换的真值表,跟着我们会绘制卡诺图,根据卡诺图我们可以得到优化后的电路。此方法适用于小型设计,但对于大型设计,此流程将变得复杂且容易出错。这就是 Verilog 的用武之地,它向我们展示了另一种方式。
低层级设计
要了解 Verilog 是如何帮助我们设计仲裁器的话,让我们继续聚焦在状态机----现在我们进入低级设计并剥开上一个框图中黑盒子的封面,来看看输入是如何影响仲裁器的。
圆圈代表仲裁器可能处于的状态,每个状态都对应一个输出。状态之间的箭头是状态转换,由导致转换的事件标记。例如,最左边的橙色箭头表示如果仲裁器处于状态 GNT0(输出对应于 GNT0 的信号)并接收到输入 !req_0时,就会移动到状态 IDLE 并输出对应于该状态的信号。这个状态机描述了你所需要的系统的所有逻辑状态。下一步是将其全部放入 Verilog 中。
模块(Modules)
我们需要回溯一下才能做到这一点。如果你观察第一张图片中的仲裁器,就会发现它有一个名称(“仲裁器”)和输入/输出端口(req_0、req_1、gnt_0 和 gnt_1)。
由于Verilog是一种HDL(硬件描述语言,一种用于集成电路概念设计的语言),它也需要具备这些东西(名称和输入/输出端口)。在 Verilog 中,我们把“黑盒子”称为模块(Modules)。这是Verilog中的保留字,用于指代具有输入、输出和内部逻辑的事物。它们是其他编程语言中具有返回值的函数(Functions)的类似概念。
“仲裁器”模块的代码
如果你仔细观察仲裁块,就会看到有许多的箭头标记(进入模块的是输入,从模块出去的则是输出)。在Verilog中,我们声明了模块名和端口名之后,就可以定义每个端口的方向了。其RTL代码如下所示。
module arbiter (
clock , // clock
reset , // Active high, syn reset
req_0 , // Request 0
req_1 , // Request 1
gnt_0 , // Grant 0
gnt_1 // Grant 1
);//-------------Input Ports-----------------------------
input clock ;
input reset ;
input req_0 ;
input req_1 ;//-------------Output Ports----------------------------
output gnt_0 ;
output gnt_1 ;
双向端口示例
上面我们只使用了两种类型的端口,输入input和输出output,此外,还有一种双向端口也可以使用----inout。
inout read_enable; // 名为 read_enable 的端口是双向的
向量(vector )信号示例
应该如何定义向量信号(由多于一位的信号组成的序列)呢?Verilog 提供了一种简单的方法。
inout [7:0] address; //端口“address”是双向的
请注意 [7:0] 意味着我们使用的是little-endian(低字节序)约定----从最右边的 0 位开始依次向左递增。
如果我们使用的是 [0:7],意味着我们使用的是big-endian(高字节序)约定----从最左边的 0 位开始依次向右递增。
Endianness (字节序)是一种决定数据“读取”方式的排序方式,不同的系统之间确实存在差异,因此始终使用正确的 endianness 很重要。作为类比,想想一些从左到右(高字节序)书写的语言(英语)与从右到左(低字节序)书写的其他语言(阿拉伯语)。了解语言的书写方向对于能够阅读它至关重要,但方向本身是在几年前任意设置的。
概括
- 我们了解了如何在 Verilog 中定义块/模块(block/module)
- 我们学习了如何定义端口和端口方向(ports and port directions)
- 我们学习了如何声明向量/标量端口(vector/scalar)
数据类型
数据类型与硬件有什么关系?实际上,没什么关系。人们只是想再写一种包含数据类型的语言。但是等等……硬件确实有两种驱动(Drivers)。驱动?那是什么?
驱动是一种可以驱动负载的数据类型。在物理电路中,驱动器基本上可以是电子可以穿过/进入的任何东西。
- 可以存储数值的驱动(例如:触发器(flip-flop))
- 不能存储值,但能连接两点的驱动(例如:线(wire))。
第一种类型的驱动在 Verilog 中称为 reg(“register”的缩写)。第二种数据类型称为线(wire)。此外还有很多其他的数据类型,例如,寄存器可以是有符号的、无符号的、浮点数……作为新手,你现在暂时不要管这些。
示例:
wire and_gate_output; // "and_gate_output" 是只输出的线
reg d_flip_flop_output;// "d_flip_flop_output" 是一个寄存器;它存储并输出数值
reg [7:0] address_bus;// "address_bus" 是一个低字节序的 8 位寄存器
概括
- Wire 数据类型用于连接两点
- Reg 数据类型用于存储数值
运算符
值得庆幸的是,verilog中的运算符与其他编程语言中的相同。他们取两个值并比较(或其他的运算方式)它们以产生第三个结果----常见的例子是加法、等于、逻辑与……为了让我们的生活更轻松,几乎所有的运算符(至少下面列表中的那些)与它们在 C 语言中的对应部分完全相同。
类型 | 符号 | 功能 |
算术运算符 | * | 乘法 |
/ | 除法 | |
+ | 加法 | |
- | 减法 | |
% | 取余 | |
+ | 一元加法(Unary plus) | |
- | 一元减法(Unary minus) | |
逻辑运算符 | ! | 逻辑非 |
&& | 逻辑与 | |
|| | 逻辑或 | |
关系运算符 | > | 大于 |
< | 小于 | |
>= | 大于等于 | |
<= | 小于等于 | |
相等运算符 | == | 等于 |
!= | 不等于 | |
归约操作符 | ~ | 按位取反 |
~& | 与非 | |
| | 或 | |
~| | 活飞 | |
^ | 异或 | |
^~ | 同或 | |
~^ | 同或 | |
移位运算符 | >> | 向右移位 |
<< | 向左移位 | |
拼接运算符 | { } | 拼接 |
条件运算符 | ? | 条件 |
示例
a = b + c ; // 这很容易
a = 1 << 5; // 嗯,让我想想,好吧,将 '1' 左移 5 个位置。
a = !b ; // 它会反转 b 吗???
a = ~b ; // 你还想给'a'赋值多少次?这可能会导致多驱动(multiple-drivers)问题。
控制语句
等等,这是什么?if, else, repeat, while, for, case----Verilog 看起来和 C 语言一模一样(或者其他你会使用的编程语言)!尽管功能上verilog看起来与 C语言相同,但 Verilog 是一种 HDL,因此描述应被转化为硬件。这意味着您在使用控制语句时必须小心(否则您的设计可能无法在硬件中实现)。
If-else语句
If-else 语句通过检查条件来决定执行哪部分代码。如果满足条件,则执行该条件对应的代码。否则,它会运行代码的其他部分。
if (enable == 1'b1) begindata = 10; //10进制赋值address = 16'hDEAD; //16进制赋值wr_enable = 1'b1; // 2进制赋值
end
else begindata = 32'b0;wr_enable = 1'b0;address = address + 1;
end
你可以在条件检查中使用任何运算符,就像 C 语言的用法一样。如果需要,我们也可以嵌套 if-else 语句。没有 else 的语句也是合法的,但是它们可能会有其他问题----在实现组合逻辑时容易产生锁存器Latch。
Case语句
当我们有一个变量需要检查多个值时,可以使用 Case 语句。就像地址解码器一样,输入是一个地址,且需要检查它的所有可能值。我们没有使用多个嵌套的 if-else 语句(一个对应于我们要查找的单个值),而是使用单个 case 语句----这类似于 C/C++ 等语言中的 Switch 语句。
Case 语句以case开头,以endcase结束。在这两个分隔符之间列出你希望执行的所有语句(后跟冒号:)。
写default语句是一个好主意,就像有限状态机 (FSM) 一样,如果进入了非定义状态,状态机就被挂起(“死机”)。带有返回功能的default语句可以保证我们的安全。
case(address)0 : $display ("It is 11:40PM");1 : $display ("I am feeling sleepy");2 : $display ("Let me skip this tutorial");default : $display ("Need to complete");
endcase
注意: if-else 和 case 语句有一个共同点----如果您没有涵盖到所有可能的情况(If-else 中没有“else”或 Case 中没有“default”),并且你正在写一个组合逻辑语句的话,那么综合工具就会推断出锁存器Latch。
While语句
如果它检查的条件为真,那么 while 语句就会重复执行其中的代码。While循环通常不用于现实电路中的模型,一般都用于测试脚本testbench。与其他语句块一样,它们由begin和end分隔。
while (free_time) begin$display ("Continue with webpage development");
end
只要 free_time 变量为真,就会重复执行 begin 和 end 内的代码----即打印“Continue with webpage development”。
让我们来看一个更奇怪的例子,它使用了大部分的 Verilog 结构。
module counter (clk,rst,enable,count);
input clk, rst, enable;
output [3:0] count;
reg [3:0] count;always @ (posedge clk or posedge rst)if (rst) begincount <= 0;end else begin : COUNTwhile (enable) begincount <= count + 1;disable COUNT;end
endendmodule
您会注意到一个名为 always 的新块----这说明了 Verilog 的一个关键特性。正如我们之前提到的,大多数软件语言都是按顺序执行的。相反,Verilog 程序通常有许多并行执行的语句。当满足其中列出的一个或多个条件时,所有标记为always 的块都将同时运行。
在上面的示例中,always 块将在 rst 或 clk 达到上升沿时运行----当它们的值从 0 上升到 1 时。您可以在程序中同时运行两个或多个always块(此处未显示,但常用)。
我们可以通过无效化保留字的方式来无效化代码块。在上面的示例中,每次计数器递增后,COUNT 代码块(此处未显示)都会被无效化。
For语句
Verilog 中的 for 循环几乎与 C/C++ 中的 for 循环完全相同。唯一的区别是 Verilog 不支持 ++ 和 -- 运算符,所以和在 C 中那样编写 i++ 不同,你需要写出完整的 i = i + 1。
for (i = 0; i < 16; i = i +1) begin$display ("Current value of i is %d", i);
end
此代码将按顺序打印从 0 到 15 的数字。将 for 循环用于RTL时要小心,需要确保你的代码实际上可以在硬件中正常实现……并且循环不是无限的。
Repeat语句
repeat 语句类似于我们刚刚介绍的 for 循环。与我们声明 for 循环时显式地指定一个变量并递增它不同,repeat语句是告诉程序应该运行代码多少次,且没有变量递增(除非我们希望它们如此,就像在这个例子中)。
repeat (16) begin$display ("Current value of i is %d", i);i = i + 1;
end
输出与前面的 for 循环程序示例完全相同。在实际硬件实现中我们一般很少使用repeat语句(或 for 循环)。
概括
- while、if-else、case(switch)语句和C语言中的一样
- If-else 和 case 语句要求涵盖组合逻辑的所有情况
- For 循环与 C 中的相同,但没有 ++ 和 -- 运算符
- Repeat 与 for 循环相同,但没有递增变量
变量赋值
在数字电路中有两种类型的电路,组合逻辑电路和时序逻辑电路。我们当然知道这一点,但问题是“我们应该如何在 Verilog 中对此建模?”。Verilog 提供了两种对组合逻辑进行建模的方法和一种对时序逻辑进行建模的方法。
- 可以使用 assign 和 always 语句对组合逻辑电路建模
- 只能使用 always 语句对时序逻辑电路建模
- 还有第三个块,仅在testbench中(实际上也可以在RTL中进行初始化,但不常见)使用:称为Initial语句。
Initial块
顾名思义,Initial块(出师快)仅在仿真开始时执行一次。这在编写testbench时很有用。如果我们有多个Initial块,那么它们都会在仿真开始时执行。
示例
initial beginclk = 0;reset = 0;req_0 = 0;req_1 = 0;
end
在上面的示例中,在仿真开始时(即当仿真时间为0 时),begin-end内的所有变量都会被赋值为零。
Always块
顾名思义,always 块总是在执行,这与仅执行一次(在仿真开始时)的Initial块不同。第二个区别是 always 块应该有一个敏感列表或与之关联的延迟。
敏感列表告诉 always 块何时执行代码块,如下图所示。保留字alway后的@符号表示代码块将在符号@后括号中的条件“触发”。
关于 always 块的一个重要说明:它不能驱动 wire 数据类型,但可以驱动 reg 和 integer 数据类型。
always @ (a or b or sel)beginy = 0;if (sel == 0) beginy = a;end else beginy = b;end
end
上面的例子是一个 2选1的多路选择器, a 和 b是输入,sel 是选择,y 是输出。
在任何组合逻辑电路中,只要输入发生变化,输出就会立即发生变化。当应用于 always 块时,该理论意味着只要输入变量(或输出控制变量)发生变化,就需要执行 always 块中的代码。这些变量是包含在敏感列表中的变量,即 a、b 和 sel。
有两种类型的敏感列表:电平敏感(用于组合电路)和边沿敏感(用于触发器)。下面的代码是相同的 2:1 Mux,但输出 y 现在是触发器输出。
always @ (posedge clk )beginif (reset == 0) beginy <= 0;end else if (sel == 0) beginy <= a;end else beginy <= b;end
end
通常情况下我们不得不复位触发器,因此每次时钟从 0 转换到 1 (posedge) 时,都要检查复位是否有效(同步复位),然后继续执行正常逻辑。
如果我们仔细观察,就会发现在组合逻辑的情况下,我们使用了“=”进行赋值;而对于时序逻辑,我们则使用了“<=”运算符。“=”是阻塞赋值,“<=”是非阻塞赋值。“=”在begin-end内顺序执行代码,而非阻塞“<=”则并行执行代码。
我们可以写一个没有敏感列表的 always 块,在这种情况下需要有一个延迟,如下面的代码所示。
always begin#5 clk = ~clk;
end
语句前面的 #5 将其延迟 5 个时间单位。
Assign块
assign 语句仅用于建模组合逻辑,并且会连续执行。所以赋值语句被称为“连续赋值语句(continuous assignment statement')”,因为其没有敏感列表。
assign out = (enable) ? data : 1'bz;
上面的例子是一个三态buffer。当使能为 1 时,数据被驱动到 out,否则 out 被拉到高阻抗。我们可以使用嵌套的条件运算符来构造多路选择器、解码器和编码器。
assign out = data;
这个例子是一个简单的buffer。
任务和函数
当一次又一次重复相同的旧事物时,Verilog 与任何其他编程语言一样,提供了解决重复使用代码的方法----任务和函数。
下面的代码可用于计算奇偶校验。
function parity;input [31:0] data;integer i;beginparity = 0;for (i= 0; i < 32; i = i + 1) beginparity = parity ^ data[i];endend
endfunction
函数和任务具有相同的语法,一个区别是任务可以有时间延迟,但函数不能。这意味着函数可用于建模组合逻辑。第二个区别是函数可以返回一个值,而任务不能。
Testbench(测试脚本)
好的,我们已经根据设计文档编写了代码,接着呢?
我们需要对其进行测试,看看它是否符合规格。大多数时候,这与我们在大学时代在数字实验室中所做的相同----驱动输入,将输出与预期值相匹配。
这是仲裁器的RTL代码:
module arbiter (
clock,
reset,
req_0,
req_1,
gnt_0,
gnt_1
);input clock, reset, req_0, req_1;
output gnt_0, gnt_1;reg gnt_0, gnt_1;always @ (posedge clock or posedge reset)
if (reset) begingnt_0 <= 0;gnt_1 <= 0;
end else if (req_0) begingnt_0 <= 1;gnt_1 <= 0;
end else if (req_1) begingnt_0 <= 0;gnt_1 <= 1;
endendmodule
这是仲裁器的Testbench:
module arbiter_tb;reg clock, reset, req0,req1;
wire gnt0,gnt1;initial begin$monitor ("req0=%b,req1=%b,gnt0=%b,gnt1=%b", req0,req1,gnt0,gnt1);clock = 0;reset = 0;req0 = 0;req1 = 0;#5 reset = 1;#15 reset = 0;#10 req0 = 1;#10 req0 = 0;#10 req1 = 1;#10 req1 = 0;#10 {req0,req1} = 2'b11;#10 {req0,req1} = 2'b00;#10 $finish;
endalways begin#5 clock = ! clock;
endarbiter U0 (
.clock (clock),
.reset (reset),
.req_0 (req0),
.req_1 (req1),
.gnt_0 (gnt0),
.gnt_1 (gnt1)
);endmodule
看起来我们已经将所有仲裁器的输入声明为 reg,将输出声明为 wire;我们这样做是因为测试平台需要驱动输入并需要监控输出。
在声明了所有需要的变量之后,我们将所有输入初始化为已知状态----这是在initial块中实现的。初始化后,我们按照要测试仲裁器的顺序断言/取消断言复位、req0、req1。时钟是用 always 块生成的。完成测试后,我们需要停止仿真----使用了 $finish 来终止仿真。$monitor 则用于监空信号列表的变化,并以我们想要的格式打印出来。
这是仿真运行后的结果:
req0=0,req1=0,gnt0=x,gnt1=x
req0=0,req1=0,gnt0=0,gnt1=0
req0=1,req1=0,gnt0=0,gnt1=0
req0=1,req1=0,gnt0=1,gnt1=0
req0=0,req1=0,gnt0=1,gnt1=0
req0=0,req1=1,gnt0=1,gnt1=0
req0=0,req1=1,gnt0=0,gnt1=1
req0=0,req1=0,gnt0=0,gnt1=1
req0=1,req1=1,gnt0=0,gnt1=1
req0=1,req1=1,gnt0=1,gnt1=0
req0=0,req1=0,gnt0=1,gnt1=0
- 📣您有任何问题,都可以在评论区和我交流📃!
- 📣本文由 孤独的单刀 原创,首发于CSDN平台🐵,博客主页:wuzhikai.blog.csdn.net
- 📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐!
相关文章:

ASIC-WORLD Verilog(1)一日Verilog
写在前面 在自己准备写一些简单的verilog教程之前,参考了许多资料----asic-world网站的这套verilog教程即是其一。这套教程写得极好,奈何没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。 这是网站原文&…...

数据治理工具项目投标书技术部分-V1.6
本资料来源公开网络,仅供个人学习,请勿商用,如有侵权请联系删除 项目背景 二、项目目标 提供一套后勤数据治理工具部署文件及配套文档,主要技术指标如下: (1)具备数据抽取转换装载、元数据管理、…...

ARMv8如何读取cache line中MOESI 状态以及Tag信息(tag RAM dirty RAM)
本文以Cortex-A53处理器为例,通过访问 处理器中的内部存储单元(tag RAM和dirty RAM),来读取cache line 中的MOESI信息。 Cortex-A53提供了一种通过读取一些系统寄存器,来访问Cache 和 TLB使用的一些内部存储单元的机制…...

学习通学习--脚本
刷客就爱学学习-首页 (xxbwk.top) 所有科目答案可以网上找超星尔雅学习通《形势与政策》2023年春章节测试答案 (3gmfw.cn) 学习通全部答案 萌面人 – 萌面人官网 (mengmianren.com) 自动答题教程 想要使用自动答题功能,只需要一个配置项就可以让OCS脚本拥有自动答…...

C盘的深度清理
随着反复安装和移除软件,c盘虽然给了80或者100G的空间,也经不住垃圾文件的堆积。居然只剩下几兆空间了。真是可气,某些软件虽然移除了。但是他们不负责自己产生的文件夹和文件的深度清理。 1. 清理系统的垃圾 2. 移动或者清理大文件。 某…...

43掌握自动化运维工具 Puppet 的基本用法,包括模块编写、资源管理
Puppet是一种自动化配置管理工具,可以自动化地部署、配置和管理大规模服务器环境。本教程将介绍Puppet的基本用法,包括模块编写和资源管理。 模块编写 在Puppet中,模块是一组相关的类、文件和资源的集合。模块可以用于部署和配置应用程序、服…...

【新2023Q2押题JAVA】华为OD机试 - 硬件产品销售方案
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:硬件产品销售方案 题目描述 …...

three.js实现3d球体树状结构布局——树状结构的实现
目录系列文章安装依赖基本分析实体类场景相机渲染器辅助线环境光点光源球形几何体球形几何体的材质线几何体线几何体的材质物体文本轨道控制实现效果实现源码参考文档系列文章 three.js实现3d球体树状结构布局——添加入场、出场、点击放大等动画 安装依赖 npm i three three…...

ChatGPT大解密:带您探讨机器学习背后的秘密、利用与发展
一、什么是机器学习?二、ChatGPT 的运作原理三、ChatGPT 生活利用1、自然语言处理2、翻译3、自动回复四、ChatGPT vs 其他相关技术五、ChatGPT 的未来1、未来发展2、职业取代3、客服人员4、翻译人员5、语言学家6、机遇与挑战六、结语这篇文章,将带着各位…...

3ds max2024带来了什么新功能(一)
文章目录1、安装2、操作界面3、快捷键(不冲突了)4、 修改器列表(可以搜索了)5、超级阵列功能(Array)6、超级布尔1、安装 传说3dmax2024有很多牛叉的改进二话不说,先安装按起来!这个…...

HNU-电路与电子学-实验3
实验三 模型机组合部件的实现(二)(实验报告格式案例) 班级 计XXXXX 姓名 wolf 学号 2021080XXXXX 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能&am…...

Hadoop MapReduce各阶段执行过程以及Python代码实现简单的WordCount程序
视频资料:黑马程序员大数据Hadoop入门视频教程,适合零基础自学的大数据Hadoop教程 文章目录Map阶段执行过程Reduce阶段执行过程Python代码实现MapReduce的WordCount实例mapper.pyreducer.py在Hadoop HDFS文件系统中运行Map阶段执行过程 把输入目录下文件…...

GitLab CI/CD 新书发布,助企业降本增效
前言 大家好,我是CSDN的拿我格子衫来, 昨天我的第一本书《GitLab CI/CD 从入门到实战》上架啦,这是业内第一本详细讲解GitLab CI/CD的书籍。 历经无数个日夜,最终开花结果。感触良多,今天就借这篇文章来谈一谈这本书的…...

【分享】如何写出整洁的代码?
文章目录前言1.为什么要保持代码整洁?1.1 所以从一开始就要保持整洁1.2 如何写出整洁的代码?2.命名3.类3.1单一职责3.2 开闭原则3.3 内聚4.函数4.1 只做一件事4.2 函数命名4.3 参数4.4 返回值4.5 怎样写出这样的函数?4.6 代码质量扫描工具5.测试5.1 TDD5.2 FIRST原则5.3 测试…...

视频剪辑:教你如何调整视频画面的大小。
大家应该都会调整图片的大小吧,那你们会调整视频画面的大小吗?我想,应该会有人不还不知道要调整的吧,今天就让小编来教大家一个方法怎样去调整视频画面的大小尺寸。 首先,我们要有以下材料: 一台电脑 【…...

操作系统概述
Overview Q1(Why):为什么要学操作系统?Q2(What):到底什么是操作系统?Q3(How):怎么学操作系统? 一.为什么要学操作系统? 学习操作系统…...

记录重启csdn
有太多收藏的链接落灰了,在此重启~ 1、社会 https://mp.weixin.qq.com/s/Uq0koAbMUk8OFZg2nCg_fg https://mp.weixin.qq.com/s/yCtLdEWSKVVAKhvLHxjeig https://zhuanlan.zhihu.com/p/569162335?utm_mediumsocial&utm_oi938179755602853888&ut…...

蓝牙耳机哪个品牌质量最好最耐用?蓝牙耳机排行榜10强推荐
现今,外出佩戴蓝牙耳机的人越来越多,各大品牌厂商对于蓝牙耳机各种性能的设计也愈发用心。那么,无线耳机哪个品牌音质好?下面,我来给大家推荐几款质量好的无线蓝牙耳机,可以当个参考。 一.南卡…...

mysql 双主架构详解
文章目录 一、背景二、MySQL双主(主主)架构方案三、MySQL双主架构图四、MySQL双主架构的优缺点五、MySQL双主架构,会存在什么问题?总结一、背景 MySQL 主从模式优缺点 容灾:主数据库宕机后,启动从数据库,用于故障切换 备份:防止数据丢失 读写分离:主数据库可以只负责…...

计算机指令系统基础 - 寻址方式详解
文章目录1 概述2 常见寻址方式2.1 立即寻址2.2 直接寻址2.3 间接寻址2.4 寄存器寻址2.5 寄存器间接寻址2.6 相对寻址2.7 变址寻址3 扩展3.1 操作码3.2 常见寄存器1 概述 计算机指令:指挥计算机工作的 指示 和 命令内容:通常一条 指令 包括两方面的内容 …...

React Three Fiber动画入门
使用静态对象和形状构建 3D 场景非常酷,但是当你可以使用动画使场景栩栩如生时,它会更酷。 在 3D 世界中,有一个称为角色装配的过程,它允许你创建称为骨架的特殊对象,其作用类似于骨骼和关节系统。 这些骨架连接到一块…...

为什么我推荐你使用 systemd timer 替代 cronjob?
概述 前几天在使用 Terraform cloud-init 批量初始化我的实验室 Linux 机器。正好发现有一些定时场景需要使用到 cronjob, 进一步了解到 systemd timer 完全可以替换 cronjob, 并且 systemd timer 有一些非常有趣的功能。 回归话题:为什么我推荐你使用 systemd t…...

elasticsearch基础6——head插件安装和web页面查询操作使用、ik分词器
文章目录一、基本了解1.1 插件分类1.2 插件管理命令二、分析插件2.1 es中的分析插件2.1.1 官方核心分析插件2.1.2 社区提供分析插件2.2 API扩展插件三、Head 插件3.1 安装3.2 web页面使用3.2.1 概览页3.2.1.1 unassigned问题解决3.2.2 索引页3.2.3 数据浏览页3.2.4 基本查询页3…...

【Linux】七、进程间通信(二)
目录 三、system V(IPC) 3.1 system V共享内存 3.1.1 共享内存的概念 3.1.2 共享内存的原理 3.1.3 创建共享内存(shmget ) 3.1.4 ftok函数 3.1.5 查看共享内存资源 3.1.6 创建共享内存测试代码 3.1.7 再次理解共享内存 3.1.8 释放共享内存(shm…...

Synchronized学习大总结
目录 1.synchronized特性 2.synchronized如何使用 3.synchronized的锁机制 1.synchronized特性 synchronized 是乐观锁,也是悲观锁,是轻量级锁(j基于自旋锁实现),也是重量级锁(基于挂起等待锁实现),它不是读写锁,是互斥锁,当一个线程抢到锁之后,其它线程阻塞等待,进入synchr…...

VN5620以太网测试——环境搭建篇
文章目录 前言一、新建以太网工程二、Port Configuration三、Link up四 Trace界面五、添加Ethernet Packet Builder六、添加ARP Packet七、添加Ethernet IG总结前言 CANoe(CAN open environment)VN5620 :是一个紧凑而强大的接口,用于以太网网络的分析、仿真、测试和验证。 …...

redis哨兵和集群部署手册
一、哨兵模式原理及作用 1.原理 哨兵(sentinel): 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现 故障时,通过投票机制选择新的master并将所有slave连接到新的master。所以整个运行哨兵的集…...

ctfshow web入门 java 295 298-300
其他没啥好讲的,都是工具就通杀了 web295 漏洞地址 http://ip/S2-048/integration/saveGangster.action 这里我们可以看到他是解析了 尝试使用网上的payload %{(#dmognl.OgnlContextDEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess#dm):((#container#cont…...

SWIG包装器使用指南——(四)C#使用SWIG简介与实践
SWIG系列:http://t.csdn.cn/cIAcr 文章目录一、简介二、全局函数、变量、常量三、继承四、传递指针、引用、数组与值五、基本类型的指针与引用六、基本类型的数组七、基本类型的默认map规则八、常用的typemap方法九、代码插入十、实践10.1 如何映射Foo*&到ref F…...

HashTable, HashMap 和 ConcurrentHashMap
HashTable, HashMap 和 ConcurrentHashMap 都是 Java 集合框架中的类,用于存储和操作键值对。它们之间存在一些关键区别,如下所示: 1.同步性: HashTable:线程安全,所有的方法都是同步的(synchr…...