• 写在前面
  • 正文

    • 左移位寄存器
    • 右移位寄存器
    • 串行输入并行输出移位寄存器
    • 并行输入串行输出移位寄存器
  • 参考资料
  • 交个朋友

写在前面

  • 个人微信大众号:FPGA LAB
  • 个人博客主页
  • 注:学习沟` l X * . ~通运用!

正文

在数字电子产品中,移位寄存器是级联的触发器,其间一个触发器的输出引脚q衔接到下一个触发器的数据输入引脚(d)。n M o } Y h | * 由于一切触发器都在同一时钟上工作,所以存储在移位寄存器中的位阵列将移位一个位置。
例如,假如一E ^ ] B j个5位右移寄存器的初始9 Q W % :值为10110,而且将移位寄存器的输入绑定到O,则下一个模式将为01011,下一个模式将为00101。

Verilog设计实例(6)基于Verilog的各种移位寄存器实现
5位移位寄存器示意图

移位寄存器的种类有很多,需求根据需求来规划,但万变不离其宗,都是每$ v ^ D r一个时钟,寄存器阵列 K E }移位一次,下面就盘点各种移位寄存器:

  1. 左移位寄存器
  2. 右移位寄存器
  3. 串行输入并行输出移位寄存器
  4. 并行输入串行输出移位寄存器

P J l z P J面就别离认识下吧。

左移位寄存器

所谓的左移,这儿约定成网K a 5 a U V 1 ( /高位移位,这是由于咱们一般界说变量都是:

reg [MSB:LS- ] ] g T t ) eB] VAR;

高位在左,底位在右,因? ` 3 R / –而左移便q ~ b y Z B R =是向高位移位。
其实这儿还能够持* 0 g T ^ O .续细分,是循环左移还是非循环的呢?

循环左移寄存器

所谓的循环左移,便是将最高& y M 9 v = 7 r位移位到最低位,次高位作K 6 _ ;为最高位,依次循环。# d 5 X O j } n 6

电路规划:

以四位循环左移为例,给出电路规划Verilog代码:

`timescale 1C v  F Z { F sns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: Reborn Lee
// ModulC , K Z he Name: cycle_left_register
// Additiog z & & enal Comments:
// hM o Mttps://blog.csdn.nu S ; E / $ | det/reborn_lee
//////////////////////////////////E ` [ x f  u///////////////////////////////////////N 7 S 8 { t v/////////


module cycle_left_register #(parameter MSB = 4)(
 inpux t &t [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 <= '8 r { ;d0;
  en/ m W [ Yd
  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;


endmodu_ Y 8 / +le

注:里面添加了! V u i ^ ~ 8 } ?一个信号,叫装载信号i_load,这个信号有效的时分,/ k B ` * C 4 s `将输入din赋值给中间寄存器dout_mid,这样才能实现每一个时钟上升沿来暂时,都对输入左移一次。

测验代码

简单给出测验代码:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: Reborn Lee
// Module Name: cycle_left_register_td  . y - Ab
// https://blog.csdn.net/reborn_lee
////////$ | o ( -  %//////////////////////////////////////////////////////////////////////////


module cycle_left_rea N 5 b & ? j * ngister_tb(

    );
 p~ W s `arameter MSB = 4;

 reg [MS$ 9 R - k J ,B - 1 : 0] din;
 reg i_d u rrst;
 reg i_clk;
 reg i_load;
 wire [MSB - 1 : 0] dout;

 //generate clock
 initial begin
  i_clk = 0;
  forever begin
   #5 i_clkG m 1 A q 9 = = ~i_clk;
  end
 end

 //generate rst and input data 
 initial( e L ] F begin
  i_rst = 1;
  din = 0;
  i_load = 0;

  # 22

  i_rst = 0;
  @(negedge i_clk) bZ p , =egin
  din = 'b1011;
  i_load = 1;
  end

  @(negedge i_clk) begin
   i_load = 0;
  end

  r; 1 + { w 5epeat(51 k e Y P ^ 5 S) @(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_m j x r u ` =  Aload = %0b, din = %b, dout = %b", iw V 2 5 ~_rst, i_load, din, dout);

 cycle_left_register #(.MSB(MSB))inst_cyP O A h 4cle_left_register(
  .ie u | v + B T ? !_clk(i_clk),
  .i_rst(i_rst),
  .i_load(i_load),
  .din(din),
  .dout(dout)
  );



endmodule

给出仿真结果:

Verilog设计实例(6)基于Verilog的各种移位寄存器实现
左移F i * ! = P ` .位寄存器仿真结果

监控记载U r i

 i_rst = 1, i_load = 0, din = 0000,; Y V O dout = xxxx
i_rst = 1, i_load =I u , Z 0, din = 0000, dout = 0000
i_rsO : ; 2 , z ! } ot = 0, i_load = 0, din = 0000, dout = 0000
i_J H }rst = 0, i_load = 1j o J G R G, 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, iA , } g . ! 9 m k_load = 0, din = 1011, doutn o M = 1110
i_rst = 0, i_load = 0, din = 1011,m y A 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_loaZ = a e e . % 6 Pd = 1, din = 0101, dout = 0101O ^ X H o @ Z
i_rst = 0, i_load = 0, din = 0101, dout# y / z c 3 = 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 = 101U ? J 3 r H # ^0
i_rst = 0, i_load =u C _ 0, din = 0101, dout = 0101

非循环左移寄存器

非循环左移对于循环左移来说,便是最高 A x S 1位不移入最低位,而是丢弃,最低位补零。
修改其间移位句子即可:

dout_mid <= {dout_mid[MSB - 2 : 0], dout_mid[MS% 1 lB - 1]};

改为:

dout_mid <= {dout_mid[MSB - 2 : 0],1'b0};

行为仿真波形

Verilog设计实例(6)基于Verilog的各种移位寄存器实现
非循= r o Q Z I环的左移移位寄存器仿真图
 i_rst = 1, i_load = 0, din = 0000, dout = xxxx
i_rst = 1, iB ` c_load = 0, din = 0000, dout = 0000
i_rstB  P } y H C = 0, i_load = 0, din{ b ;  = 0000, dout = 0000
i_rst = 0, i_load = 1, din = 1011, dout = 0000
i_rst = 0,7 % J i_load = 1l 0  m V V G L D, din = 1011,- ` q H T g j k W dout = 1011
i_rst = 0, i_load = 0, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din = 1011Q - L a w 9 s,b x v H @ p u + ` 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 =f j _ Q W P D , P 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

注意事项:

循环移位句子:

dout_mid <= {dout_mid7 G d @ ?[MSB - 2 : 0],1'b0};

其间的最低位一定要写成1’b0,假如写成了0,即:

dout_mid <= {dout_mid[MSB - 2 :& E / D C / ] 0],0};

则仿真结果变为:

Verilog设计实例(6)基于Verilog的各种移位寄存器实现
非循环左移的4位移位寄存器仿真图异常情况

这意味着,直接赋值0给! 5 O l P 2 n q `dout_mid了。

右移位寄存器

右移位寄存器和左移位寄存器是对称的,便是每一个时钟上升沿到来,1 % 0 8 g 4 Y }都向低位移动一次,这儿也必要重新写了,咱们只需求改其间某条移位句子即可。

这儿又分为循环与不循环,别离点出。

循环右移位

即:

dout_mid <= {dout_mid[MSB - 2 : 0], do C out_mid[MSB - 1]};

改为:

dout_mid <= {dout_mid[0] x ? {  g ? h $, dout_ma Y 5 D  C mid[MSB - 1 : 1]};

为了照顾新手,还是给出完整规划代码:

`timescale 1ns / 1ps
///////////////v , @ - ! !/////////////* 0 J b A O/////////////////////////////////////////v H 0 */////////////
// Engineer: Reborn Lee
// Module Name: cycle_left_register
// AdF + c Sditional CommeH ; w 6 Cnts:
// https://b[ s M E B 1 2log.csdn.net/reborn_lee
///////////////////////////////////////////////////////6 , v b  f d : S///////////////////////////


module shift_register #(parameter MSB = 4)(
 inpuO % T =t [MSB - 1 : 0] dinU G  F = C,
 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_mi5 s }d <= 'd0;
  e! f F A } * v ^nd
  else if(i_load)p , x { begin
   dout_mid <= din;
  end
  else begin
   // dout_mid <= {dout_mid[MSB - 2 : 0], 1'b0}; // normal left shq L g oift
   // 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;


endmodul~ H a / 1e

仿真波形:

由于仿真文件和上述的循环f = g q M k h 1左移一致,就改一下例化即可,这儿就没必要给出了 ,直接给~ r P ^ 9 _ D +出仿真波形:

Verilog设计实例(6)基于Verilog的各种移位寄存器实现
循环右移寄存器仿真波形

监控记载

 i_rst = 1, i_load = 0, din = 0000,T Q 9 l dout = xxxx
i_rst = 1, i_load = 0, din = 0000, doutc q d U = 0000
i_rst = 0, i_load = 0, din = 0000,{ 7 5 J F ( ^ * d dout = 0000
iv R l $_rst = 0, i_load = 1, din = 1011, dout = 0000
i_rst = 0, i_lo, 7 5 Kad = 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 = 1011s l s { r H L ^ @, dout = 0111
i_rst = 0, i_load = 0, di& Z n * ) ~ rn = 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_loaG 2 _ n d , 9 Jd = 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

非循环右% $ :移寄存器

相对于循环右移寄存器来说,只需求改动为:最高位补零即可。
即:
将移位句子:


dout_mid <=u ) U ^ {dout_mid[0],dout_mid[MSB - 1 : 1]};

改为:

dout_k X d ` J - 6mid <= {1'b0,dout_mid[MSB - 1 : 1]};

仿真波形为:K _ ) I g z x % e

Verilog设计实例(6)基于Verilog的各种移位寄存器实现
非循环右移寄存器

监控记载

 i_r3 / D cst = 1, i_load| h : Q  9 Q I = 0, din = 0000, dout = xxxx
i_rst = 1, i_load = 0, din = 0000, dout = 0000
i_rst = 0, i_load = 0, diT x un = 0000, dout = 0000
i_rst = 0, i_load = 1, din = 1011, dout = 0000
i_rst = 0, i_loF F M M % F ] 4ad = 1, din = 1011, dout = 1011
i_rst = 0, i_load = 0, din =o S Q E - { q  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, do2 - # ( aut = 0001
i_rst = 0, i_load = 0, din h 1 * k o y = 101F S S x & 3 Q ( z1, dout = 0000
i_rst = 0, i_load = 1, din = 0101, dout = 0000
i_rst = 0, i_load = 1,E g l X x k # din = 0101, dout = 0101
i_rst = 0, i_load = 0, din = 0101, dout = 0101
i_rst = 0, iy ^ *_load = 0, din = 0101, dout = 0010
i_rst = 0, i_load = 0, din = 0101, dout = 0001
i_? T yrst = 0, i_load = 0, din = 0101, dout =$ 1 F $ ( f 0000

串行输入并行输出移位寄存器

Verilog设计实例(6)基于Verilog的各种移位寄存器实现
3位串行输出并行输出移j W ~ R `位寄存器示意图

该移位寄存器规划具有五个4 + _ Y _ v ]输入和一个n位输出,而且运用参数MSB对规划进行参数化以表明移位寄存器的宽度。 假如MSB为4,则它成为4位移* 4 F ( i o J @ q位寄存器。 假如MSB为8,则它成为8位移n e + : R k x J _位寄存器。
该移位寄存器具有一些关键功能F f { ) )

  • 可经过l / K驱动规划的en信号来启用或禁用
  • 驱动dir时可左右移动
  • 假如将rstn拉y E X c 为低电平,则会重置移位寄存器,输出将变为0
  • 移位寄存器的输入数据值能l = + – V @够经过d引脚操控

因而,这儿没有必要再将左移位以及右移位分开来写了,合在一个规划里,经过一个信号dir操控,dir为0,左移,不然,右移!

规划代码


`timescalJ X C Qe 1ns / 1ps
/////////////////////////S P @/////////////////////////////////////////////////////////
// Engineer: Reborn Lee
// Module Name: shift_register
// https://blog.csdn.n * ~ ^net/reborn_lee
/////////////////////////////////////////. W J (  + R/////////////////////////////////////////


module shift_rey = Cgister+ r L 3 : v l Q -#(parameter MSB = 8)(
 input i_clk,
 input i_rst,
 inpv # Y H S H u }ut i_dir,
 input i_en,
 input din,+ F b T & [
 output reg [MA I zSB - 1 : 0] dout

    );

 ale O S ( j ( ^ 2 Nways @(posedge i_clk) begin
  if (i_rs3 ] B m G 4 xt) begin
   // reset
   dout <= 'd0;
  end
  else if (i_en) begin
   case(i_dir)
    0: begin //left shift
     dout <= {doutv Y B W d g[MS| / N j o P lB - 2: 0], din};
    end
    1: bev , s : Q I )gin
     dout <= {din, dout[MSB - 1 : 1]};
    end
   endcase

  end
  else begin
   dout <= dout;
  end
 end

endmodule

仿5 I i真代码

`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

 init@ L ;ial begin
  i_rst = 1;~ L @ P d
  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
   @(c h 3 W d Ynegedge iA + = $ + 8 I ( e_clk) begin
    din = $random;
   end
  end
  # 20 $finish;


 end



 shift_register #(.MSB(MSB))inst_shift_reg@ i W u o 4 j 1ister (
  .i_clk(i_clk),
  .i__ 4 erst(i_rst),[ B , S
  .i_df 5 W ^ir(i_dir),
  .i_en(i_en),
  .din(din),
  .dout(dout)

  );





endmodule

仿真波形

Verilog设计实例(6)基于Verilog的各种移位寄存器实现
左移
Verilog设计实例(6)基于Verilog的各种移位寄存器实现
右移

并行输入串行输出移位寄存器

并行输入串行输出的原理图如下:

Verilog设计实例(6)基于Verilog的各种移位寄存器实现
3位的并行输i A y ^ R入串行输出移位寄存器示意图

该电路由三个串联的D触发器组成。 这意味着,一个D触发器的输出被衔接为下一个D触发器的输入。 一切这些触发器彼此同步,由于相同的时钟# W = % 0 %信号被施加到每个/ g h ; N T触发器。

在该移位寄存器M W ( V & @ G d o中,咱们能够经过将Preset Enable(预置使能)设7 u Q # s 3 B #为1,将并行输入@ 4 { Y应用于每个D触发器。对于时钟信号的每个正沿触发,数据都会从一个级转移到下一个级。 因而,咱们将从最右边的D触发器获P q j Y取串行输出。

于此一起,咱们依然设置一个操控方向的使能信号i_dir,假@ k m x T如i_dir为0,则并行输出左移,取最高位作为串行输出;d ^ ) 5 g z不然,右移,取最低位作为串行输出。

电路规划


//paralell input and serial output shift register
module shift_register#(paQ $ O m y Q &ramb ? D i 8 F ; oeter MSB = 4)(
 input i_clk,
 input i_load,
 input i_dir,
 input [MF V E D y ;SB - 1 : 0]+ 5 p l H P W din,
 output dout
 );

 reg [MSB - 1 : 0] q_mid = 0;
 always@(posedge i_clk)n g X n 9 $ ` z u begin
   if(i_load) begin
    q_mid <= din;
   end
   else be) @ f ; Sgin
    case(i_dir)
    1'ba t G 7 ~ d0: 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

 aL D ` O p $ssign dout = i_dir ? (q_mid[0]) : (q_mid[MSB - 1]);


endmodule

仿真文件

`times* ! Bcale`  A k * [ n M = 1ns/1ps
module shift_registe{ L + w ur_tb;
 parameter MSB = 4;

    re4 : S ; ng iW p w + 8 k [ `_clk;
 reg i_dir;
 reg i_load;# { % D s 
 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 = $rag =  d Q 5 D cndom;
  i_load = 1;

  @(negedge i_clk) i_n ^ ] x b [ b | =load = 0;
  i_dir = 1;

  repeat(3) begin
   @(negedgeQ T d G f 5 i_clk);
  end
  # 20 $finish;


 end

// Monitor valuu 7 T * R =es of these variables and prg E s O * { Dint 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_registeb / Z ! ? ~ ) n .r(
  .i_clk(i_clk),
  .i_dir(i_dir),
  .i_load(i_load),
  .din(din),
  .dout(dout)

  );





endmodule
Verilog设计实例(6)基于Verilog的各种移位寄存器实现
4bit并行输入串行输出移位寄存器

监控数据

i_loa] Z } d % q od=0, i_dir=0, din=0100,   dout = 0
i_load=1, i_dir=0, din=0100,   d, . G } * ,out = 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,S R ) G 2 m 8   dout = 0
i_load=0, i_dir=1,K & 3 s t ! c din=0001,   dout = 1
i_load=0, i_dir=1, din=0001,   dout = 0

参考资料

  • 参考资料1
  • 参考资料2
  • 参考资料3

交个朋友

  • 个人微信大众号:FPGA LAB,左下角二维码;

  • 知乎:李锐博恩,右下角二维码。 v . b
    Verilog设计实例(6)基于Verilog的各种移位寄存器实现

  • FPGA/IC技术沟通2020