🌈以下是本人对循环移位算法的理解,是为了方便后续的学习,如有补充和错误,欢迎评论区留言!

循环移位


1. 循环移位的介绍

下面以FPGA入门的流水灯实验为例详细介绍什么是循环移位。初始状态时,四位流水灯为全灭状态,假设流水间隔为0.5s,则0.5s之后,最左边led灯点亮,其余全灭,再经过0.5s后,第二位led点亮,其余全灭,依次类推,最右边led的亮,其余全灭;接下来要循环该过程,即0.5s之后,最左边led灯点亮,其余全灭,这样就实现了流水灯的效果。表示效果如下:

🌑🌑🌑🌕 --0.5s--> 🌑🌑🌕🌑 --0.5s--> 🌑🌕🌑🌑 --0.5s--> 🌕🌑🌑🌑--0.5s--> 🌑🌑🌑🌕 --0.5s-->.....

如果这四位led灯是共阴极,那么上述效果转化为电平,即为:

0 0 0 1 --0.5s--> 0 0 1 0 --0.5s--> 0 1 0 0 --0.5s--> 1 0 0 0 --0.5s--> 0 0 0 1 --0.5s-->.....

这种电平呈现一种循环且左右移位的操作就称为循环移位。


2. 循环移位逻辑及代码实现

说到移位,首先会想到逻辑移位运算符">>“和”<<“,但是该运算符只能实现单方向的移位,不能实现循环的效果,如果想要实现循环,需要加上其他判断语句,加大了工作量。在Verilog语法中,有一种位拼接运算符”{}",它可以实现变量高位和低位的转换。具体实现操作如下:

1
2
3
assign a = 4'b0010;
assign b = {a[1],a[3:2],a[0]};
assign c = {a[2:0],a[3]};
1
2
3
a = 4'b0010;
b = 4'1000;
c = 4'b0100;

根据Verilog提供的位拼接运算符,我们就可以轻松实现循环移位了,左移那么我们就将最高位往最低为移动,右移就将最低位往最高位移动即可。

⌨️循环右移代码演示
1
2
3
4
5
6
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led <= 4'b0001;
else
led <= {led[0],led[3:1]};
end
⌨️循环左移代码演示
1
2
3
4
5
6
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led <= 4'b0001;
else
led <= {led[2:0],led[3]};
end
🧮循环右移结果展示
初始状态第一个时钟上升沿第二个时钟上升沿第三个时钟上升沿第四个时钟上升沿第n个时钟上升沿
🌑🌑🌑🌕🌕🌑🌑🌑🌑🌕🌑🌑🌑🌑🌕🌑🌑🌑🌑🌕
🧮循环左移结果展示
初始状态第一个时钟上升沿第二个时钟上升沿第三个时钟上升沿第四个时钟上升沿第n个时钟上升沿
🌑🌑🌑🌕🌑🌑🌕🌑🌑🌕🌑🌑🌕🌑🌑🌑🌑🌑🌑🌕

3. 循环移位在FPGA其他方面的应用

循环移位的应用是非常广泛的,就在不久前,我使用FPGA做了一个计数器,用数码管显示计数的数字,从0到999,到达999之后重新计数。数码管有4位,但是我们的位选信号只有一位,这是为了节约FPGA宝贵的IO资源,因此我们我们在显示时,需要对位选信号不断循环移位。