HDLbits筆記-Shift Registers
4-bit shift register
题目:设计一个4-bit移位寄存器(右移),采用异步复位,同步load,enable模式。
(1)复位后,移位寄存器输出0;
(2)load为高电平,将data[3:0]数据load进移位寄存器;
(3)ena为高电平,移位寄存器右移一位;
(4)q作为移位寄存器的输出;
如果load和ena信号同时有效,load信号优先级较高。
module top_module(
input clk,
input areset, // async active-high reset to zero
input load,
input ena,
input [3:0] data,
output [3:0] q);
reg [3:0] q_temp;
always@(posedge clk or posedge areset)begin
if(areset)
q_temp <= 4'd0;
else if(load)
q_temp <= data;
else if(ena)
q_temp <= (q_temp >> 1);
else
q_temp <= q_temp;
end
assign q = q_temp;
endmodule
Rotate 100
题目:设计一个带有同步load和左右使能enable的100-bit的左右旋转器。旋转器从寄存器的另一端插入已移出的位,不像移位器丢弃已移出的位而插入一个零。如果启用,旋转器会旋转这些位并且不会修改/丢弃它们。
(1)laod:加载data[99:0]到移位寄存器中;
(2)ena[1:0]选择旋转的方向:2’b01向右旋转一个bit;2’b10向左旋转一个bit;2’b00,2’b11不旋转
(3)q作为旋转器的输出
module top_module(
input clk,
input load,
input [1:0] ena,
input [99:0] data,
output reg [99:0] q);
always@(posedge clk)begin
if(load)
q <= data;
else begin
case(ena)
2'b00: q <= q;
2'b01: q <= {q[0],q[99:1]};
2'b10: q <= {q[98:0],q[99]};
2'b11: q <= q;
endcase
end
end
endmodule
注意移位的方法,q>>1表示将q中的最低位移除,在最高位补0;而q <= {q[0],q[99:1]}表示将q的最低位直接移到q的最高位。
Left/right arithmetic shift by 1 or 8
题目:设计一个带有同步load功能的64bit的算数移位寄存器。既可以左移又可以右移,通过amount信号选择移位的位数。算术右移在移位寄存器(在本例中是q[63])中移动数字的符号位,而不是像逻辑右移那样移动零。算术右移的另一种思考方式是假设被移动的数有符号并且保留符号,因此算术右移可以将有符号的数除以2的幂。
逻辑左移和算数左移没有区别。
(1)load为高电平将data[63:0]加载到移位寄存器中;
(2)ena选择是否移位操作;
(3)amount移位方向及移位多少位;
2’b00: shift left by 1 bit.
2’b01: shift left by 8 bits.
2’b10: shift right by 1 bit.
2’b11: shift right by 8 bits.
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)begin
if(load)
q <= data;
else if(ena)begin
case(amount)
2'b00: q <= q << 1;
2'b01: q <= q << 8;
2'b10: q <= {q[63],q[63:1]};
2'b11: q <= {{8{q[63]}},q[63:8]};
endcase
end
end
endmodule
总结:
(1)q << n等价于乘以2^n;
(2)q >> n 等价于除以2^n;
(3) q <<< n 等价于乘以2^n;
(4)q >>> n 等价于除以2^n;
对于逻辑左移右移和算数左移,只需要把腾出的位补0;而在算数右移中,如果左操作数是无符号数,则腾出的位用0填充;如果是有符号数,则腾出的位用最高位填充。
5-bit LFSR
题目:
module top_module(
input clk,
input reset, // Active-high synchronous reset to 5'h1
output [4:0] q
);
always@(posedge clk)begin
if(reset)
q <= 5'd1;
else begin
q[4] <= 0 ^ q[0];
q[3] <= q[4];
q[2] <= q[0] ^ q[3];
q[1] <= q[2];
q[0] <= q[1];
end
end
assign q = {q[4],q[3],q[2],q[1],q[0]};
endmodule
32-bit LFSR
题目:在5-bit FSR基础上,构建一个32-bit的LFSR
module top_module(
input clk,
input reset, // Active-high synchronous reset to 32'h1
output [31:0] q
);
integer i,j;
always@(posedge clk)begin
if(reset)
q <= 32'd1;
else begin
q[31] <= 0 ^ q[0];
for(i = 30 ;i > 21; i = i - 1)begin
q[i] <= q[i+1];
end
q[21] <= q[0] ^ q[22];
for(i = 20 ;i > 1; i = i - 1)begin
q[i] <= q[i+1];
end
q[1] <= q[0] ^ q[2];
q[0] <= q[0] ^ q[1];
end
end
assign q = {q[31],q[30],q[29],q[28],q[27],q[26],q[25],q[24],q[23],q[22],q[21],q[20],q[19],q[18],q[17],q[16],q[15],
q[14],q[13],q[12],q[11],q[10],q[9],q[8],q[7],q[6],q[5],q[4],q[3],q[2],q[1],q[0]};
endmodule
注意中间没有反馈的部分可以采用for循环的形式,还要注意是在什么地方反馈的。
或者这样写代码,简单一些:
module top_module(
input clk,
input reset, // Active-high synchronous reset to 32'h1
output [31:0] q
);
always@(posedge clk)begin
if(reset)
q <= 32'd1;
else
q <= {0^q[0],q[31:23],q[0]^q[22],q[21:3],q[0]^q[2],q[0]^q[1]};
end
endmodule
Shift register
题目:
module top_module (
input [3:0] SW,
input [3:0] KEY,
output [3:0] LEDR
); //
MUXDFF MUXDFF0(
.clk (KEY[0]),
.w (KEY[3]),
.R (SW[3]),
.E (KEY[1]),
.L (KEY[2]),
.Q (LEDR[3])
);
MUXDFF MUXDFF1(
.clk (KEY[0]),
.w (LEDR[3]),
.R (SW[2]),
.E (KEY[1]),
.L (KEY[2]),
.Q (LEDR[2])
);
MUXDFF MUXDFF2(
.clk (KEY[0]),
.w (LEDR[2]),
.R (SW[1]),
.E (KEY[1]),
.L (KEY[2]),
.Q (LEDR[1])
);
MUXDFF MUXDFF3(
.clk (KEY[0]),
.w (LEDR[1]),
.R (SW[0]),
.E (KEY[1]),
.L (KEY[2]),
.Q (LEDR[0])
);
assign LEDR = {LEDR[3],LEDR[2],LEDR[1],LEDR[0]};
endmodule
module MUXDFF (
input clk,
input w, R, E, L,
output Q
);
always@(posedge clk)begin
if(L)begin
Q <= R;
end
else begin
if(E)begin
Q <= w;
end
else begin
Q <= Q;
end
end
end
endmodule
在模块例化是的时候千万注意连线,这道题目很可能会把w信号连错,开始和KEY[3]连接,之后上一个模块的输出作为新的w输入,即和LEDR[3]连接,以此类推。
3-input LUT
题目:
首先用8个D触发器创建一个8-bit移位寄存器。每个D触发器的输出标记为Q[0]…q[7]。S作为移位寄存器的输入,Q[0]作为输入。enable信号控制是否移位。此外,电路还有三个额外的输入A,B,C和一个输出Z。当ABC为000时,Z= Q[0],当ABC为001时,Z= Q[1],以此类推。设计的电路只能包括8-bit的移位寄存器和选择器。这个电路也叫3-input的LUT。
module top_module (
input clk,
input enable,
input S,
input A, B, C,
output Z );
integer i;
reg [7:0] Q;
always@(posedge clk)begin
if(enable)begin
Q <= {Q[6:0],S};
end
else
Q <= Q;
end
always@(*)begin
case({A,B,C})
3'b000: Z = Q[0];
3'b001: Z = Q[1];
3'b010: Z = Q[2];
3'b011: Z = Q[3];
3'b100: Z = Q[4];
3'b101: Z = Q[5];
3'b110: Z = Q[6];
3'b111: Z = Q[7];
endcase
end
endmodule
这里的case 语句还可以写为:
assign Z = Q[{A,B,C}];