【IC设计】移位寄存器
目录
- 理论讲解
- 背景介绍
- 什么是移位寄存器
- 按工作模式分类
- verilog语法注意事项
- 设计实例
- 循环移位寄存器
- 算术双向移位寄存器
- 5位线性反馈移位寄存器
- 伪随机码发生器
- 3位线性反馈移位寄存器
- 32位线性反馈移位寄存器
- 串行移位寄存器(打4拍)
- 双向移位寄存器:二选一+移位寄存器
- 3 输入查找表 (LUT)
- Rule90
- Rule110
- Conwaylife康威的生命游戏
- 参考链接
图片来源:寒武纪魔道电子【移位寄存器是如何工作的,为什么它能把串行信号转成并行】
理论讲解
背景介绍
早期的硬盘为IDE并行接口,如今的电子设备多以串行接口接收信号,如温度传感器DS18B20为串行总线、采用串行接口AD采样芯片会极大节省CPU的I/O口。那具体的串行数据是如何被读入CPU内部呢?
答案就是通过移位寄存器实现!
什么是移位寄存器
移位寄存器是一种时序逻辑电路,能够存储和传输数据。它们由触发器组成,这些触发器的连接方式使得一个触发器的输出可以作为另一个触发器的输入,具体取决于所创建的移位寄存器的类型。移位寄存器基本上是一种能够传输(“移位”)数据的寄存器。寄存器通常是存储设备,它们是通过将特定数量的触发器串联在一起而创建的,并且寄存器可以存储的数据量(位数)始终与触发器的数量成正比,因为每个触发器一次只能存储一个bit。当寄存器中的触发器以这样的方式连接时,一个触发器的输出成为另一个触发器的输入,就会创建一个移位寄存器。
触发器是具有类似于闩锁操作的设备,被称为双稳态电路,有两个稳定的状态,即0或1,并且能够以bit为单位存储数据。每当D触发器的时钟发生变化时(上升沿或下降沿,取决于触发器的规格)。输出“Q”处的数据与输入“D”处的数据相同。触发器的输出“Q”将保持在该值,直到下一个时钟周期,然后它将再次更改为输入处的值(1或0)。
有关触发器的具体介绍请进入传送门: 【IC设计】时序逻辑的基础—锁存器、触发器
按工作模式分类
移位寄存器主要根据其工作模式(串行或并行)分为几类。下面列出了几种基本移位寄存器,尽管其中一些可以根据数据流的方向进一步划分,右移或者左移。
传送门:[PDF]移位寄存器及其应用 - 中国科学技术大学
- 串口输入—串口移位寄存器 (SISO)
- 串行输入—并行输出移位寄存器 (SIPO)
- 并联输入—并联输出移位寄存器 (PIPO)
- 并联输入—串行移位寄存器 (PISO)
- 双向移位寄存器
verilog语法注意事项
如果在赋值语句中需要左右移位,尽量不要用语法中提供的左移“<<”和右移“>>”符号
因为不同的综合工具对他们的处理方式不同,导致逻辑综合的结果不可控,即使代码通过了功能仿真和FPGA验证,也有可能在ASIC实现时出问题。最稳妥的移位方法要把每位的移动具体写出来.
例如,向右循环移位可写为(a[6:0]<=a[7:1];a[7]<=a[0]),由于这种写法落实到具体的位,所以逻辑综合的结果将不依赖于EDA工具,这样命运就会掌握在自己的手里,不用去关心EDA工具如何处理左右移位。
------ 引用自《CMOS模拟集成电路全流程设计》 李金城 机械工业出版社
设计实例
循环移位寄存器
构建一个100位的左右旋转器,同步load,左右旋转需使能。旋转器从另一端输入移位的位元,不像移位器那样丢弃移位的位元而以零位移位。如果启用,旋转器就会旋转这些位,而不会修改或丢弃它们。
load:加载100位的移位寄存器数据
ena[1:0]:2’b01 右转1bit; 2’b10 左转1bit;其他情况不转
q:旋转器内容
- 代码实现
module top_module(input clk,input load,input [1:0] ena,input [99:0] data,output reg [99:0] q); always@(posedge clk)beginif(load == 1'b1)beginq <= data;end else begin
/* if(ena == 2'b01)beginq <= {q[0], q[99:1]};end if(ena == 2'b10)beginq <= {q[98:0], q[99]};endif(ena == 2'b00 && ena == 2'b11)beginq <= q; endend*/case(ena)2'b01: q <= {q[0], q[99:1]};2'b10: q <= {q[98:0], q[99]}; default: q <= q; endcaseendend
endmodule
算术双向移位寄存器
-
4位双向移位寄存器真值表
-
建立一个64位算术移位寄存器,同步加载。移位器可以左右移位,并按数量选择1位或8位的移位。
1、算术右移将移位移位寄存器中数字(在本例中为q[63])的符号位,而不是逻辑右移所做的零。
2、另一种考虑算术右移的方法是它假设被移的数是有符号的并保留符号,所以算术右移可以将一个有符号的数除以2的幂。
load:加载数据
ena:决定是否移位
amount:决定移位方向与数量:2’b00:左移1位;2’b01:左移8位;2’b10:右移1位;2’b11:右移8位
q:寄存器内容(输出)
- 代码实现
module top_module(input clk,input load,input ena,input [1:0] amount,input [63:0] data,output reg [63:0] q); always@(posedge clk)beginif(load == 1'b1)beginq <= data;end else beginif(ena == 1'b1)begincase(amount)2'b00: //shift left by 1 bitq <= {q[62:0], 1'b0};2'b01: //shift left by 8 bitsq <= {q[55:0], 8'b0};2'b10: //shift right by 1 bitq <= {q[63], q[63:1]}; 2'b11: //shift right by 8 bitsq <= {{8{q[63]}}, q[63:8]}; //default: endcaseend else beginq <= q;endendend
endmodule
- 验证结果
5位线性反馈移位寄存器
线性反馈移位寄存器(LFSR)主要包括:
- Galois(内部LFSR),又称one-to-many
- 斐波那契(外部LFSR),又称many-to-one
1、其中,gn为反馈系数,取值只能为0或1,取为0时表明不存在该反馈之路,取为1时表明存在该反馈之路;
2、这里的反馈系数决定了产生随机数的算法的不同。
3、用反馈函数表示成y = a0x^0 + a1x + a2x^2…
4、反馈函数为线性的叫线性移位反馈序列,否则叫非线性反馈移位序列。
5、Q1、Q2、Q3、Qn为LFSR的输出,M(x)是输入的码字多项式,如M(x)=x^4+ x^1+ 1,表示输入端的输入顺序为11001,同样,LFSR的结构也可以表示为多项式G(x),称为生成多项式:G(x) = gn * x^n+ …+g1 * x^1+ g0;
练习:
构造线性移位寄存器,reset应当使LFSR归1。
- 代码实现
module top_module(input clk,input reset, // Active-high synchronous reset to 5'h1output [4:0] q
); always@(posedge clk)beginif(reset == 1'b1)beginq <= 5'h1;end else beginq[4] <= q[0] ^ 1'b0;q[3] <= q[4];q[2] <= q[3] ^ q[0];q[1] <= q[2];q[0] <= q[1];endend
endmodule
- 验证结果
伪随机码发生器
同样,异名例化,用计数器的方法定义时钟
3位线性反馈移位寄存器
为这个序列电路编写Verilog代码。假设你要在DE1-SoC板上实现这个电路。将R输入连接到SW开关,将时钟连接到密钥[0],将L连接到密钥[1],将Q输出连接到红灯LEDR上。
注:该电路是线性反馈移位寄存器(LFSR) 的一个示例。最大周期 LFSR 可用于生成伪随机数,因为它在重复之前循环 2 n -1 个组合。全零组合不会出现在此序列中。
- 代码实现
//方法1:RTL级描述
module top_module (input [2:0] SW, // Rinput [1:0] KEY, // L and clkoutput reg [2:0] LEDR); // Qwire D0,D1,D2;assign D0 = KEY[1] ? SW[0] : LEDR[2];assign D1 = KEY[1] ? SW[1] : LEDR[0];assign D2 = KEY[1] ? SW[2] : (LEDR[2]^LEDR[1]);always@(posedge KEY[0])beginLEDR[0] <= D0;LEDR[1] <= D1;LEDR[2] <= D2;end
endmodule
//方法2:RTL级描述,例化子模块
module top_module (input [2:0] SW, // Rinput [1:0] KEY, // L and clkoutput [2:0] LEDR); // Qwire w1,w2,w3;assign w1 = KEY[1] ? SW[0] : LEDR[2];assign w2 = KEY[1] ? SW[1] : LEDR[0];assign w3 = KEY[1] ? SW[2] : LEDR[1]^LEDR[2];D_flipflop ins0(w1, KEY[0], LEDR[0]);D_flipflop ins1(w2, KEY[0], LEDR[1]);D_flipflop ins2(w3, KEY[0], LEDR[2]);
endmodule//构建D触发器模块
module D_flipflop(input D, input clk, output Q);always @(posedge clk)beginQ <= D;end
endmodule
//二路选择器很简单,用三目运算符即可
//方法3:行为级描述,用if-else代替多路选择器
module top_module (input [2:0] SW, // Rinput [1:0] KEY, // L and clkoutput [2:0] LEDR); // Qalways@(posedge KEY[0]) beginif(KEY[1]) beginLEDR[0] <= SW[0]; LEDR[1] <= SW[1];LEDR[2] <= SW[2];endelse beginLEDR[0] <= LEDR[2]; LEDR[1] <= LEDR[0];LEDR[2] <= LEDR[1] ^ LEDR[2]; endendendmodule
32位线性反馈移位寄存器
构建一个32位的Galois LFSR,其taps位置为32、22、2和1。
当移位寄存器位数较多,需要使用向量,而不是一一写出32个DFF
- 代码实现
module top_module(input clk,input reset, // Active-high synchronous reset to 32'h1output reg [31:0] q
); integer i;always@(posedge clk)beginif(reset == 1'b1)beginq <= 32'h1;end else beginfor(i=0; i<32; i=i+1)beginif(i==21 || i==1 || i==0)beginq[i] <= q[i+1] ^ q[0];end else if(i==31)beginq[i] <= 1'b0 ^ q[0];end else beginq[i] <= q[i+1];//q[i] <= q[i+1];endendendend
endmodule
串行移位寄存器(打4拍)
- 代码实现
module top_module (input clk,input resetn, // synchronous resetinput in,output out);reg [2:0] q;always@(posedge clk)beginif(!resetn)begin{q,out} <= 4'd0;end else begin{q,out} <= {in,q};endendendmodule
双向移位寄存器:二选一+移位寄存器
- 子模块代码设计
module MUXDFF (input clk,input w, R, E, L,output Q
);always@(posedge clk)beginQ <= L ? R :E ? w :Q ;end
endmodule
- 顶层模块代码设计
module top_module (input [3:0] SW,input [3:0] KEY,output [3:0] LEDR
); //MUXDFF u_n(.clk(KEY[0]), .w(KEY[3]/LEDR[n]), .E(KEY[1]), .R(SW[n]), .L(KEY[2]), .q(LEDR[n]));MUXDFF u_3(.clk(KEY[0]), .w(KEY[3] ), .E(KEY[1]), .R(SW[3]), .L(KEY[2]), .q(LEDR[3]));MUXDFF u_2(.clk(KEY[0]), .w(LEDR[3]), .E(KEY[1]), .R(SW[2]), .L(KEY[2]), .q(LEDR[2]));MUXDFF u_1(.clk(KEY[0]), .w(LEDR[2]), .E(KEY[1]), .R(SW[1]), .L(KEY[2]), .q(LEDR[1]));MUXDFF u_0(.clk(KEY[0]), .w(LEDR[1]), .E(KEY[1]), .R(SW[0]), .L(KEY[2]), .q(LEDR[0]));endmodule
3 输入查找表 (LUT)
在这个问题中,你将为一个8x1存储器设计一个电路,在这个电路中,写入到存储器是通过移位来完成的,而读取是“随机访问”,就像在一个典型的RAM中一样。然后您将使用该电路实现一个3输入逻辑功能。
首先,用8个d类型触发器创建一个8位移位寄存器。标记为Q[0]到Q[7]。移位寄存器输入称为S,输入Q[0] (MSB先移位)。使能输入enable控制是否移位,扩展电路使其有3个额外的输入A,B,C和一个输出Z。电路的行为应该如下:当ABC为000时,Z=Q[0],当ABC为001时,Z=Q[1],以此类推。你的电路应该只包含8位移位寄存器和多路选择器。(这个电路称为3输入查找表(LUT))。
module top_module (input clk,input enable,input S,input A, B, C,output Z );
// The final circuit is a shift register attached to a 8-to-1 mux.reg [7:0] q;// Create a 8-to-1 mux that chooses one of the bits of q based on the three-bit number {A,B,C}:assign Z = q[{A,B,C}];// Edge-triggered always block: This is a standard shift register (named q) with enable.
// When enabled, shift to the left by 1 (discarding q[7] and and shifting in S).always@(posedge clk)beginif(enable == 1'b1)beginq <= {q[6:0], S};end else beginq <= q;endendendmodule
- 验证结果
Rule90
各单元的下一状态是此时当前单元相邻两位的异或。
在这个电路中,创建一个512单元系统(q(511:0)),并在每个时钟周期中前进一个时间步长。加载(load)表明系统的状态应该加载data[511:0]至q中,假设边界(q[0]和q[512])都为零。
- 代码设计
//方法1,数组类似于水管,for循环类似于套在管子上的滑轨
module top_module(input clk,input load,input [511:0] data,output [511:0] q ); integer i;always@(posedge clk)beginif(load == 1'b1)beginq <= data;end else beginq[0] <= q[1] ^ 1'b0;q[511] <= q[510] ^ 1'b0;for(i=1; i<511; i=i+1)begin //i:510~1q[i] <= q[i+1] ^ q[i-1];end endend
endmodule
//方法二,给数组的每对数进行异或
module top_module(input clk,input load,input [511:0] data,output reg [511:0] q);always @(posedge clk) beginif (load)q <= data; // Load the DFFs with a value.else begin// left right// neighbour neighbourq <= {1'b0, q[511:1]} ^ {q[510:0], 1'b0} ;endend
endmodule
- 验证结果
Rule110
与上题类似,状态转移条件发生变化,如下图所示:
根据真值表写出卡诺图并化简:OUT = Center ^ Right + ( ~Left &Center )
module top_module(input clk,input load,input [511:0] data,output [511:0] q
); integer i;always@(posedge clk)beginif(load == 1'b1)beginq <= data;end else beginq[0] <= (q[0]) || (q[0]& ~q[1]);;q[511] <= (q[511]^q[510]) || (q[511]);;for(i=1;i<511;i=i+1)begin//i = 1; i<511;i=i+1q[i] <= (q[i]^q[i-1]) || (q[i]& ~q[i+1]);endendend
endmodule
- 代码验证
Conwaylife康威的生命游戏
作为前两题的升级版,本题的变换工作在一个二维矩阵上,是一个二维序列生成器。
游戏规则如下:元素的下一个状态取决于当前状态九宫格中的 8 个邻居元素中 1 的个数,当邻居有 n 个 1 时:
0-1 ,元素变为 0
2 ,元素保持不变
3 ,元素变为 1
4+ ,元素变为 0
方便做题起见,本题中的这个二维矩阵设定为 16x16,广义上可以是无限的。
为了让事情变得更加有趣,这个16x16 矩阵的边界进行循环处理,回卷到对边,打个比方,上边界的上一行为下边界,左边界的左一列为右边界。
上下边界回卷示意,左右边界同理所以对元素 (0,0) 来说,共有 8 个邻居 : (15,1), (15,0), (15,15), (0,1), (0,15), (1,1), (1,0) 以及 (1,15)。
这个 16x16 矩阵表示为 256bit 长度的向量 q,其中 q[15:0] 代表第一行,q[31:16] 代表第二行,以此类推。
HDLBit 支持使用 SystemVerilog,所以你也可以使用二维向量表示这个矩阵。load 信号有效时,更新 q 信号值为初始值 data, q 每个周期变换一次。
- 解题思路
本题笔者采用一分为 2 的思路:
统计矩阵中每个元素的 8 -相邻元素中 1 的个数
根据相邻元素中的 1 的个数,决定元素下一状态的值
使用组合逻辑,采用相加的方式计算相邻元素中 1 的个数,使用一个 256 长的序列来记录每个元素相邻元素中 1 的个数,最大为 8 个,所以每个元素使用 3 bit 来记录。
wire [2:0] nghbr_num [255:0];
在统计时,需要处理边界绕回的的特殊情况。对于边界上的元素,根据绕回的规则确立边界。需要特殊处理的是第一/最后一行/列。在编写 Verilog 代码时,可以对这几种情况分别确立边界。
因为不想代表显得太冗长,这里引入了 4 个整形变量 idx_i_d, idx_i_u, idx_j_r, idx_j_l ,在不同的情况下,来确立四条边界。
idx_i_u = (i == 0) ? i-1+16 :i-1; //up idx
idx_i_d = (i == 15)? i+1-16 :i+1; //down idx
idx_j_l = (j == 0) ? j-1+16 :j-1; //left idx
idx_j_r = (j == 15)? j+1-16 :j+1; //right idx
使用时序逻辑,根据统计的结果,决定下一周期元素的值。
输出最终结果时,将二维信号重新转换为一维信号,Verilog 不支持直接在一维/二维信号之间赋值。
- 代码设计
module top_module(input clk,input load,input [255:0] data,output [255:0] q ); reg [15:0] q_2d[15:0]; wire [2:0] nghbr_num [255:0];int idx_i_u, idx_i_d, idx_j_l, idx_j_r;int i,j;//count num of neighboursalways@(*)beginfor(i=0; i<16; i=i+1)beginfor(j=0; j<16; j=j+1)beginidx_i_u = (i == 0) ? i-1+16 : i-1;//up idxidx_i_d = (i == 15) ? i+1-16 : i+1;//down idx idx_j_l = (j == 0) ? j-1+16 : j-1;//left idxidx_j_r = (j == 15) ? j+1-16 : j+1;//right idxnghbr_num[i*16+j] = q_2d[idx_i_u][idx_j_l] + q_2d[idx_i_u][j] + q_2d[idx_i_u][idx_j_r]+ q_2d[i][idx_j_l] + q_2d[i][idx_j_r]+ q_2d[idx_i_d][idx_j_l] + q_2d[idx_i_d][j] + q_2d[idx_i_d][idx_j_r];endendend//next state transform base on num of neighoursalways@(posedge clk)beginif(load == 1'b1)begin:initfor(i=0; i<16; i=i+1)beginfor(j=0; j<16; j=j+1)beginq_2d[i][j] <= data[i*16+j];endend end else begin:set_valfor(i=0; i<16; i=i+1)beginfor(j=0; j<16; j=j+1)beginif(nghbr_num[i*16+j] < 2)beginq_2d[i][j] <= 'd0; end else if(nghbr_num[i*16+j] == 3)beginq_2d[i][j] <= 'd1; end else if(nghbr_num[i*16+j] > 3)beginq_2d[i][j] <= 'd0; end else begin q_2d[i][j] <= q_2d[i][j]; end endend endend//outputalways@(*)beginfor(i=0; i<16; i=i+1)beginfor(j=0; j<16; j=j+1)beginq[i*16+j] = q_2d[i][j];endend end
endmodule
参考链接
- HDLBits第十章
- 《CMOS模拟集成电路全流程设计》 李金城 机械工业出版社
- 移位寄存器
- HDLBits:在线学习 Verilog (二十四 · Problem 115-119)
相关文章:

【IC设计】移位寄存器
目录 理论讲解背景介绍什么是移位寄存器按工作模式分类verilog语法注意事项 设计实例循环移位寄存器算术双向移位寄存器5位线性反馈移位寄存器伪随机码发生器3位线性反馈移位寄存器32位线性反馈移位寄存器串行移位寄存器(打4拍)双向移位寄存器࿱…...

【Flutter 开发实战】Dart 基础篇:最基本的语法内容
在深入了解 Dart 这门编程语言之前,我们需要了解一些关于 Dart 的最基本的知识,像是常量、变量、函数等等,这样才能够让我们的开发效率更上一层楼。在本节,我们将探讨一些基础语法,包括入口方法 main、变量、常量以及命…...

中国光伏展
中国光伏展是中国最大的光伏产业展览会,每年在国内举办一次。该展览会汇集了国内外光伏行业的领先企业和专业人士,展示最新的光伏技术、产品和解决方案。 中国光伏展旨在促进光伏行业的发展和创新,提升光伏产业的国际竞争力。展览会涵盖了光伏…...

Nacos的统一配置管理
Nacos的统一配置管理 一 项目添加nacos和bootstrap依赖二 nacos客户端配置2.1 创建命名空间2.2 创建配置 三、配置bootstrap.yml四 不同环境配置切换步骤一:nacos中添加开发、测试配置步骤二:指定bootstrap.yml中spring.profiles.active参数值 扩展链接 …...

SpringBoot项目docker镜像生成
1. 本文思路 拉取基础镜像基于镜像创建容器在容器中,安装所需依赖部署脚本提交容器,生成新的镜像编写Dockerfile,添加启动命令,生成最终镜像导出镜像 2. 操作步骤 2.1 基础环境 # 拉取镜像 docker pull centos:7.6.1810 # 运行…...

JDBC初体验(二)——增、删、改、查
本课目标 理解SQL注入的概念 掌握 PreparedStatement 接口的使用 熟练使用JDBC完成数据库的增、删、改、查操作 SQL注入 注入原理:利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行能力,它可以通过在…...
Eva.js是什么(互动小游戏开发)
前言 Eva.js 是一个专注于开发互动游戏项目的前端游戏引擎。 易用:Eva.js 提供开箱即用的游戏组件供开发人员立即使用。是的,它简单而优雅! 高性能:Eva.js 由高效的运行时和渲染管道 (Pixi.JS) 提供支持,这使得释放设…...
监听 beforeunload 事件,阻止页面刷新导致的信息丢失
尤其是一个有编辑器的页面,可以监听 windwo.beforeunload 事件,在用户试图关闭当前标签页的时候提醒用户,内容可能会丢失。 Window:beforeunload 事件 - Web API 接口参考 | MDN...

Java 常见缓存详解以及解决方案
一. 演示Mybatis 一级缓存 首先我们准备一个接口 两个实现的方法, 当我们调用这个queryAll()方法时我们需要调用selectAll()方法来查询数据 调用此接口实现效果 这个时候我们就可以发现了问题,我们调用方法…...

Golang 交叉编译之一文详解
博客原文 文章目录 Golang 中的交叉编译不同操作系统间的编译Linux 下编译windowsmacos windows 下编译Linuxmacos macos 下编译Linuxwindows 不同架构下的编译amd64x86 参考 Golang 中的交叉编译 在 Golang 中,交叉编译指的是在同一台机器上生成针对不同操作系统或…...

最新ThinkPHP版本实现证书查询系统,实现批量数据导入,自动生成电子证书
前提:朋友弄了一个培训机构,培训考试合格后,给发证书,需要一个证书查询系统。委托我给弄一个,花了几个晚上给写的证书查询系统。 实现功能: 前端按照姓名手机号码进行证书查询证书信息展示证书展示&#x…...
windows安装运行Apache James(基于spring的版本)
下载地址 下载列表 https://james.apache.org/download.cgi 直接下载基于spring版本 https://www.apache.org/dyn/closer.lua/james/server/3.8.0/james-server-app-3.8.0-app.zip 设置签名 解压,并切换到james-server-spring-app-3.8.0目录下,在powe…...
Elasticsearch 基本概念:快速入门指南【记录】
简单记录,后续整理补充 介绍: Elasticsearch是一个分布式、可扩展、实时的搜索和分析引擎,建立在开源搜索库Lucene之上。它提供了强大的全文搜索功能和复杂的分析能力,适用于各种场景,包括应用日志分析、电子商务搜索…...

【JVM 基础】类字节码详解
JVM 基础 - 类字节码详解 多语言编译为字节码在JVM运行Java字节码文件Class文件的结构属性从一个例子开始反编译字节码文件字节码文件信息常量池方法表集合类名 再看两个示例分析try-catch-finallykotlin 函数扩展的实现 源代码通过编译器编译为字节码,再通过类加载…...

【算法】基础算法001之双指针
👀樊梓慕:个人主页 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 🌝每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.数组分块…...

[力扣 Hot100]Day2 字母异位词分组
题目描述 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 出处 思路 这题有点考阅读理解,意思就是把输入数组中的所含字母相同但顺序不同的单词放到同…...
记一次 easyswoole 热重载失效复盘 grpc扩展惹的祸
首先看一下运行环境 swoole version 4.8.11 php version 7.4.33 easyswoole version 3.4.6 在easyswoole 的入口文件 如下: <?php namespace EasySwoole\EasySwoole; use App\WebSocket\WebSocketEvents; use Ap…...
存储过程从表中获取数据库名称
---------------业务数据库信息 CREATE TABLE [dbo].[app_erp_datbabase_conf] ( [id] [int] IDENTITY(1,1) NOT NULL, [database_type] [varchar](200) NOT NULL, [database_name] [varchar](200) NOT NULL, [create_time] [datetime] NULL, [modify_t…...

.NET 反射的介绍和简单应用
什么是反射? 反射就是动态发现类型信息的能力。它帮助程序设计人员在程序运行时利用一些信息去动态地使用类型,这些信息在设计时是未知的,这种能力类似于后期绑定。反射还支持的更高级的行为,能在运行时动态创建新类型࿰…...

在drawio中使用BPMN2.0绘制详细的业务流程图和编排模型
在drawio中使用BPMN2.0绘制详细的业务流程图和编排模型 drawio是一款强大的图表绘制软件,支持在线云端版本以及windows, macOS, linux安装版。 如果想在线直接使用,则直接输入网址draw.io或者使用drawon(桌案), drawon.cn内部完整的集成了drawio的所有功…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...