- Writing in the front
- The body of the
- Left shift register
- Right shift register
- Serial input parallel output shift register
- Parallel input serial output shift register
- The resources
- Hand over a friend
Writing in the front
- Personal wechat official account: FPGA LAB
- Personal Blog Homepage
- Note: Learn to use!
The body of the
In digital electronics, the shift register is a cascade of flip-flops in which the output pin Q of one flip-flop is connected to the data input pin (D) of the next. Because all flip-flops work on the same clock, the bit array stored in the shift register shifts by one position. For example, if a 5-bit right-shift register has an initial value of 10110 and the input to the shift register is bound to O, the next mode will be 01011 and the next mode will be 00101.
There are many types of shift registers, which need to be designed according to the requirements, but all changes are the same, each clock, register array shift once, the following inventory of various shift registers:
- Left shift register
- Right shift register
- Serial input parallel output shift register
- Parallel input serial output shift register
The following are known respectively.
Left shift register
The so-called left shift is defined as a net high shift, because we usually define variables as:
reg [MSB:LSB] VAR;
Copy the code
The high position is to the left and the base is to the right, so a shift to the left is a shift to the high position. You can actually subdivide it further, is it cyclic left or is it acyclic?
Loop left shift register
The so-called circular left shift is to shift the highest position to the lowest position, the second highest position as the highest position, in turn.
Circuit design:
Take the four-digit cycle shift as an example, the circuit design Verilog code is given:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: Reborn Lee
// Module Name: cycle_left_register
// Additional Comments:
// https://blog.csdn.net/reborn_lee ////////////////////////////////////////////////////////////////////////////////// module cycle_left_register #(parameter MSB = 4) ( input [MSB - 1 : 0] din, input i_rst, input i_load, input i_clk, output [MSB - 1 : 0] dout ); reg [MSB - 1 : 0] dout_mid; always@ (posedge i_clk) begin if(i_rst) begin dout_mid <= 'd0; end else if(i_load) begin dout_mid <= din; end else begin dout_mid <= {dout_mid[MSB - 2 : 0], dout_mid[MSB - 1]}; end end assign dout = dout_mid; endmodule Copy the code
Note: there is a signal called load signal i_load. When this signal is valid, the input din is assigned to the intermediate register dout_mid, so that the input is moved left once for each rising edge of the clock.
The test code
The test code is given briefly:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: Reborn Lee
// Module Name: cycle_left_register_tb
// https://blog.csdn.net/reborn_lee
////////////////////////////////////////////////////////////////////////////////// module cycle_left_register_tb( ); parameter MSB = 4; reg [MSB - 1 : 0] din; reg i_rst; reg i_clk; reg i_load; wire [MSB - 1 : 0] dout; //generate clock initial begin i_clk = 0; forever begin #5 i_clk = ~i_clk; end end //generate rst and input data initial begin i_rst = 1; din = 0; i_load = 0; # 22 i_rst = 0; @ (negedge i_clk) begin din = 'b1011; i_load = 1; end @ (negedge i_clk) begin i_load = 0; end repeat(5) @ (posedge i_clk); @ (negedge i_clk) begin din = 'd0101; i_load = 1; end @ (negedge i_clk) i_load = 0; repeat(4) @ (posedge i_clk); #10 $finish; end initial $monitor (" i_rst = %0b, i_load = %0b, din = %b, dout = %b", i_rst, i_load, din, dout); cycle_left_register #(.MSB(MSB))inst_cycle_left_register( .i_clk(i_clk), .i_rst(i_rst), .i_load(i_load), .din(din), .dout(dout) ); endmodule Copy the code
Simulation results are given:
Monitoring records:
i_rst = 1, i_load = 0, din = 0000, dout = xxxx
i_rst = 1, i_load = 0, din = 0000, dout = 0000
i_rst = 0, i_load = 0, din = 0000, dout = 0000
i_rst = 0, i_load = 1, din = 1011, dout = 0000
i_rst = 0, i_load = 1, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din = 1011, dout = 0111
i_rst = 0, i_load = 0, din = 1011, dout = 1110
i_rst = 0, i_load = 0, din = 1011, dout = 1101
i_rst = 0, i_load = 0, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din = 1011, dout = 0111
i_rst = 0, i_load = 1, din = 0101, dout = 0111
i_rst = 0, i_load = 1, din = 0101, dout = 0101
i_rst = 0, i_load = 0, din = 0101, dout = 0101
i_rst = 0, i_load = 0, din = 0101, dout = 1010
i_rst = 0, i_load = 0, din = 0101, dout = 0101
i_rst = 0, i_load = 0, din = 0101, dout = 1010
i_rst = 0, i_load = 0, din = 0101, dout = 0101
Copy the code
Acyclic left shift register
Acyclic left shift for cyclic left shift, the highest digit is not moved to the lowest digit, but discarded, and the lowest digit is added to zero. Modify the shift statement:
dout_mid <= {dout_mid[MSB - 2 : 0], dout_mid[MSB - 1]};
Copy the code
To:
dout_mid <= {dout_mid[MSB - 2 : 0],1'b0};
Copy the code
Behavior simulation waveform
i_rst = 1, i_load = 0, din = 0000, dout = xxxx
i_rst = 1, i_load = 0, din = 0000, dout = 0000
i_rst = 0, i_load = 0, din = 0000, dout = 0000
i_rst = 0, i_load = 1, din = 1011, dout = 0000
i_rst = 0, i_load = 1, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din = 1011, dout = 0110
i_rst = 0, i_load = 0, din = 1011, dout = 1100
i_rst = 0, i_load = 0, din = 1011, dout = 1000
i_rst = 0, i_load = 0, din = 1011, dout = 0000
i_rst = 0, i_load = 1, din = 0101, dout = 0000
i_rst = 0, i_load = 1, din = 0101, dout = 0101
i_rst = 0, i_load = 0, din = 0101, dout = 0101
i_rst = 0, i_load = 0, din = 0101, dout = 1010
i_rst = 0, i_load = 0, din = 0101, dout = 0100
i_rst = 0, i_load = 0, din = 0101, dout = 1000
i_rst = 0, i_load = 0, din = 0101, dout = 0000
Copy the code
Matters needing attention:
Circular shift statement:
dout_mid <= {dout_mid[MSB - 2 : 0],1'b0};
Copy the code
The lowest order must be written as 1’b0. If 0 is written, that is:
dout_mid <= {dout_mid[MSB - 2 : 0],0}; Copy the code
Then the simulation result becomes:
So that means I’m just assigning 0 to dout_mid.
Right shift register
The right shift register and the left shift register are symmetric, that is, each rising edge of the clock is moved to the lower one, here also need to rewrite, we only need to change one of the shift statement.
This is divided into cycles and non-cycles.
Cyclic right shift
That is:
dout_mid <= {dout_mid[MSB - 2 : 0], dout_mid[MSB - 1]};
Copy the code
To:
dout_mid <= {dout_mid[0], dout_mid[MSB - 1 : 1]};
Copy the code
For the benefit of beginners, here is the full design code:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: Reborn Lee
// Module Name: cycle_left_register
// Additional Comments:
// https://blog.csdn.net/reborn_lee ////////////////////////////////////////////////////////////////////////////////// module shift_register #(parameter MSB = 4) ( input [MSB - 1 : 0] din, input i_rst, input i_load, input i_clk, output [MSB - 1 : 0] dout ); reg [MSB - 1 : 0] dout_mid; always@ (posedge i_clk) begin if(i_rst) begin dout_mid <= 'd0; end else if(i_load) begin dout_mid <= din; end else begin // dout_mid <= {dout_mid[MSB - 2 : 0], 1'b0}; // normal left shift // dout_mid <= {dout_mid[MSB - 2 : 0], dout_mid[MSB - 1]}; //cycle left shift dout_mid <= {dout_mid[0],dout_mid[MSB - 1 : 1]}; end end assign dout = dout_mid; endmodule Copy the code
Simulation waveform:
Since the simulation file is consistent with the above circular left shift, just change the example, there is no need to give here, directly give the simulation waveform:
Monitoring records
i_rst = 1, i_load = 0, din = 0000, dout = xxxx
i_rst = 1, i_load = 0, din = 0000, dout = 0000
i_rst = 0, i_load = 0, din = 0000, dout = 0000
i_rst = 0, i_load = 1, din = 1011, dout = 0000
i_rst = 0, i_load = 1, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din = 1011, dout = 1101
i_rst = 0, i_load = 0, din = 1011, dout = 1110
i_rst = 0, i_load = 0, din = 1011, dout = 0111
i_rst = 0, i_load = 0, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din = 1011, dout = 1101
i_rst = 0, i_load = 1, din = 0101, dout = 1101
i_rst = 0, i_load = 1, din = 0101, dout = 0101
i_rst = 0, i_load = 0, din = 0101, dout = 0101
i_rst = 0, i_load = 0, din = 0101, dout = 1010
i_rst = 0, i_load = 0, din = 0101, dout = 0101
i_rst = 0, i_load = 0, din = 0101, dout = 1010
i_rst = 0, i_load = 0, din = 0101, dout = 0101
Copy the code
Acyclic right shift register
As opposed to cyclic right shift register, only need to change to: highest bit fill zero. That is, shift the statement:
dout_mid <= {dout_mid[0],dout_mid[MSB - 1 : 1]};
Copy the code
To:
dout_mid <= {1'b0,dout_mid[MSB - 1 : 1]};
Copy the code
Simulation waveform is:
Monitoring records
i_rst = 1, i_load = 0, din = 0000, dout = xxxx i_rst = 1, i_load = 0, din = 0000, dout = 0000 i_rst = 0, i_load = 0, din = 0000, dout = 0000 i_rst = 0, i_load = 1, din = 1011, dout = 0000 i_rst = 0, i_load = 1, din = 1011, dout = 1011 i_rst = 0, i_load = 0, din = 1011, dout = 1011 i_rst = 0, i_load = 0, din = 1011, dout = 0101 i_rst = 0, i_load = 0, din = 1011, dout = 0010 i_rst = 0, i_load = 0, din = 1011, dout = 0001 i_rst = 0, i_load = 0, din = 1011, dout = 0000 i_rst = 0, i_load = 1, din = 0101, dout = 0000 i_rst = 0, i_load = 1, din = 0101, dout = 0101 i_rst = 0, i_load = 0, din = 0101, dout = 0101 i_rst = 0, i_load = 0, din = 0101, dout = 0010 i_rst = 0, i_load = 0, din = 0101, dout = 0001 i_rst = 0, i_load = 0, din = 0101, dout = 0000 Copy the code
Serial input parallel output shift register
The shift register design has five inputs and an N-bit output, and the design is parameterized with the parameter MSB to indicate the width of the shift register. If MSB is 4, it becomes a 4-bit shift register. If MSB is 8, it becomes an 8-bit shift register. The shift register has some key functions.
- This can be enabled or disabled by driving the designed EN signal
- Dir can be moved left and right when driving
- If you pull the RSTN to low, the shift register is reset and the output is 0
- The input data value of the shift register can be controlled by the D pin
Therefore, there is no need to write left shift and right shift separately here, in one design, controlled by a signal dir, dir is 0, move left, otherwise, move right!
Design code
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: Reborn Lee
// Module Name: shift_register
// https://blog.csdn.net/reborn_lee ////////////////////////////////////////////////////////////////////////////////// module shift_register#(parameter MSB = 8) ( input i_clk, input i_rst, input i_dir, input i_en, input din, output reg [MSB - 1 : 0] dout ); always@ (posedge i_clk) begin if (i_rst) begin // reset dout <= 'd0; end else if (i_en) begin case(i_dir) 0: begin //left shift dout <= {dout[MSB - 2: 0], din}; end 1: begin dout <= {din, dout[MSB - 1 : 1]}; end endcase end else begin dout <= dout; end end endmodule Copy the code
The simulation code
`timescale 1ns/1ps
module shift_register_tb;
parameter MSB = 8;
reg i_clk;
reg i_rst; reg i_dir; reg i_en; reg din; wire [MSB - 1 : 0] dout; initial begin i_clk = 0; forever begin # 5 i_clk = ~i_clk; end end initial begin i_rst = 1; i_en = 0; i_dir = 0; din = 0; # 18 @ (negedge i_clk) begin i_rst = 0; i_en = 1; end repeat(8) begin @ (negedge i_clk) begin din = $random; end end @ (negedge i_clk) begin i_rst = 1; end #18 i_rst = 0; i_dir = 1; repeat(8) begin @ (negedge i_clk) begin din = $random; end end # 20 $finish; end shift_register #(.MSB(MSB))inst_shift_register ( .i_clk(i_clk), .i_rst(i_rst), .i_dir(i_dir), .i_en(i_en), .din(din), .dout(dout) ); endmodule Copy the code
The simulation waveform
Parallel input serial output shift register
The schematic diagram of parallel input serial output is as follows:
The circuit consists of three D triggers in series. This means that the output of one D-trigger is connected to the input of the next d-trigger. All of these triggers synchronize with each other because the same clock signal is applied to each trigger.
In this shift register, we can apply parallel input to each D trigger by setting Preset Enable to 1. For each forward edge trigger of the clock signal, data is transferred from one level to the next. Therefore, we will get serial output from the right-most D trigger.
At the same time, we still set a control direction of the enable signal i_DIR, if i_DIR is 0, the parallel output moved to the left, take the highest bit as the serial output; Otherwise, move right and take the lowest order as serial output.
Circuit design
//paralell input and serial output shift register
module shift_register#(parameter MSB = 4) ( input i_clk,
input i_load,
input i_dir, input [MSB - 1 : 0] din, output dout ); reg [MSB - 1 : 0] q_mid = 0; always@ (posedge i_clk) begin if(i_load) begin q_mid <= din; end else begin case(i_dir) 1'b0: begin q_mid <= {q_mid[MSB - 2 : 0].1'b0}; //no cycle end 1'b1: begin q_mid <= {1'b0, q_mid[MSB - 1 : 1]}; //no cycle end endcase end end assign dout = i_dir ? (q_mid[0]) : (q_mid[MSB - 1]); endmodule Copy the code
The simulation file
`timescale 1ns/1ps
module shift_register_tb;
parameter MSB = 4;
reg i_clk;
reg i_dir; reg i_load; reg [MSB - 1 : 0] din; wire dout; initial begin i_clk = 0; forever begin # 5 i_clk = ~i_clk; end end initial begin i_load = 0; i_dir = 0; din = $random; # 18 @ (negedge i_clk) begin i_load = 1; end @ (negedge i_clk) i_load = 0; repeat(3) @ (negedge i_clk); //finish shift output din = $random; i_load = 1; @ (negedge i_clk) i_load = 0; i_dir = 1; repeat(3) begin @ (negedge i_clk); end # 20 $finish; end // Monitor values of these variables and print them into the logfile for debug initial $monitor ("i_load=%0b, i_dir=%0b, din=%b, dout = %0b", i_load, i_dir, din, dout); shift_register #(.MSB(MSB))inst_shift_register( .i_clk(i_clk), .i_dir(i_dir), .i_load(i_load), .din(din), .dout(dout) ); endmodule Copy the code
Monitoring data
i_load=0, i_dir=0, din=0100, dout = 0
i_load=1, i_dir=0, din=0100, dout = 0
i_load=0, i_dir=0, din=0100, dout = 0
i_load=0, i_dir=0, din=0100, dout = 1
i_load=0, i_dir=0, din=0100, dout = 0
i_load=1, i_dir=0, din=0001, dout = 0
i_load=0, i_dir=1, din=0001, dout = 1
i_load=0, i_dir=1, din=0001, dout = 0
Copy the code
The resources
- Reference 1
- Resources 2
- Resources 3
Hand over a friend
-
Personal wechat public account: FPGA LAB, QR code at the lower left corner;
-
Zhihu: Li Ruiboen, qr code in the lower right corner.
-
FPGA/IC technology communication 2020