状态机实例-寄存器拷贝
在计算机系统中,有大量的寄存器,用来保存运行过程中的数据。如果要交换两个寄存器的内容,则通常会使用第三个寄存器为临时寄存器的方法。比如,假设要交换寄存器R1,R2的内容,可以先将R2的内容传递到第三个寄存器R3,然后将R1的内容传到R2,最后将R3的内从传递到R1。
计算机系统的存储器通常是通过下图所示的内部网络互联的。除了与网络互联的信号线,每个寄存器还有两个控制信号,Rkout和Rkin。Rkout使得寄存器Rk的内容传输至互联网络,Rkin信号使得互联网络上的数据传输至寄存器Rk。Rkout和Rkin通过有限状态机控制电路产生。在下图电路中,我们设计当w=1时候,交换寄存器R1和R2的内容,数据交换完成时候输出Done信号。Clock是时钟信号。
数据转换过程如下步骤:控制信号R2out=1,R3in=1, R2的内容传到到R3,然后R1out=1,R2in=1,R1的内容传输到R2,最后,R3out=1,R1in=1,R3的内容传输到R1,完成两个寄存器内容交换,交换完成后,设置信号Done=1。假设交换的初始条件是产生一个时钟周期的脉冲信号,则时序电路状态图如下。
初始状态A中,没有信号传输,所有的输出信号为0,电路一直保持该状态,直到w变为1产生交换请求。在状态B中,执行R2的内容传输到R3中的请求信号生效,数据在下一个时钟有效沿传送至R3。不管w为0或者1,在这个时钟沿也使得状态进入C。在状态C中,执行R1的内容传输到R2中的请求信号生效,数据在下一个时钟有效沿传送至R2。不管w为0或者1,在这个时钟沿也使得状态进入D。在状态D中,执行R3的内容传输到R1中的请求信号生效,数据在下一个时钟有效沿传送至R1。不管w为0或者1,在这个时钟沿也使得状态进入A。
由于有4个状态,所以需要2个状态变量y1,y2,最直接的分配是将状态A,B,C,D分别分配为y2y1=00,01,10,11。下面的是该电路的状态表
现在状态 | 下一状态 | 输出 | |||||||
w=0 | w=1 | R1out | R1in | R2out | R2in | R3out | R3in | Done | |
A | A | B | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | C | C | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
C | D | D | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
D | A | A | 0 | 1 | 0 | 0 | 1 | 0 | 1 |
现在状态 | 下一状态 | 输出 | ||||||||
w=0 | w=1 | |||||||||
y2y1 | Y2Y1 | Y2Y1 | R1out | R1in | R2out | R2in | R3out | R3in | Done | |
A | 00 | 00 | 01 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 01 | 10 | 10 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
C | 10 | 11 | 11 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
D | 11 | 00 | 00 | 0 | 1 | 0 | 0 | 1 | 0 | 1 |
Y1 | Y1=w~y1+y2~y1 | |||
w/y2y1 | 00 | 01 | 11 | 10 |
0 | 0 | 0 | 0 | 1 |
1 | 1 | 0 | 0 | 1 |
Y2 | Y2=~y2y1+y2~y1 | |||
w/y2y1 | 00 | 01 | 11 | 10 |
0 | 0 | 1 | 0 | 1 |
1 | 0 | 1 | 0 | 1 |
根据这些状态表,我们可以得到如下的输出表达式:
Y1=w~y1+y2~y1
Y2=~y2y1+y2~y1
R2out=R3in=~y2y1
R1out=R2in=y2~y1
R1in=R3out=Done=y2y1
实现的时序电路如下:
如果我们用10表示D,11表示C,则状态表如下:
现在状态 | 下一状态 | 输出 | ||||||||
w=0 | w=1 | |||||||||
y2y1 | Y2Y1 | Y2Y1 | R1out | R1in | R2out | R2in | R3out | R3in | Done | |
A | 00 | 00 | 01 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 01 | 11 | 11 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
C | 11 | 10 | 10 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
D | 10 | 00 | 00 | 0 | 1 | 0 | 0 | 1 | 0 | 1 |
Y1的真值表:
w/y2y1 | 00 | 01 | 11 | 10 |
0 | 0 | 1 | 0 | 0 |
1 | 1 | 1 | 0 | 0 |
Y2的真值表:
w/y2y1 | 00 | 01 | 11 | 10 |
0 | 0 | 1 | 1 | 0 |
1 | 0 | 1 | 1 | 0 |
通过卡诺图简化,最终得到如下表达式,相比上面的表达式,这个实现方式要简单一点。
Y1=w~y2+~y2y1=(w+y1)~y2
Y2=y1
R2out=R3in=~y2y1
R1out=R2in=y2y1
R1in=R3out=Done=y2~y1
实现的电路图如下:
如果用独热码表示状态,则需要四个触发器。用独热码表示的状态表为:
现在状态 | 下一状态 | 输出 | ||||||||
w=0 | w=1 | |||||||||
y4y3y2y1 | Y4Y3Y2Y1 | Y4Y3Y2Y1 | R1out | R1in | R2out | R2in | R3out | R3in | Done | |
A | 0001 | 0001 | 0010 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 0010 | 0100 | 0100 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
C | 0100 | 1000 | 1000 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
D | 1000 | 0001 | 0001 | 0 | 1 | 0 | 0 | 1 | 0 | 1 |
我们可以从状态框图中推导出输出表达式:
不包括复位,有两个弧线进入状态A,这两个弧线表明,如果FSM已经在状态A,且w=0时,触发器y1应该被设置为1,或者FSM已经在状态D,所以Y1=~wy1+y4,同理,如果现在状态时A,且w=1,则触发器y2被设置为1,从而Y2=wy1,如果当前状态是B或C,触发器y3和y4分别被设置为1,从而Y3=y2,Y4=Y3。输出表达式如下:
R1out=R2in=y3
R1in=R3out=Done=y4
R2out=R3in=y2
通常用独热码表示,虽然用的触发器数量可能增多,但得到的输出表达式则相对简单,相应组合电路的实现变得简单了。
采用独热码的实现电路为:
moore型寄存器交换的verilog代码如下:
module st_moore(clk, Rst_n, w, R1in,R1out,R2in,R2out,R3in,R3out,Done); input clk; input Rst_n; input w; output R1in,R1out,R2in,R2out,R3in,R3out,Done; reg [1:0] y,Y; parameter [1:0] A=2'b00,B=2'b01,C=2'b10,D=2'b11; //得到下一个状态的组合电路 always @(w,y) begin case(y) A: if(w) Y=B; else Y=A; B: Y=C; C: Y=D; D: Y=A; endcase end always @(posedge clk, negedge Rst_n) if(Rst_n==0) y<=A; else y<=Y; //定义输出 assign R2out=(y==B); assign R3in=(y==B); assign R1out=(y==C); assign R2in=(y==C); assign R3out=(y==D); assign R1in=(y==D); assign Done=(y==D); endmodule
testbench代码:
`timescale 1ns/1ns `define clock_period 20 module regswap_tb; reg clk=0; reg Rst_n; reg w; wire R1in,R1out,R2in,R2out,R3in,R3out,Done; st_moore st_moore0(.clk(clk),.Rst_n(Rst_n),.w(w),.R1in(R1in),.R1out(R1out),.R2in(R2in),.R2out(R2out),.R3in(R3in),.R3out(R3out),.Done(Done)); always #(`clock_period/2) clk=~clk; initial begin Rst_n=1; w=0; #(`clock_period) w=1; Rst_n=0; #(`clock_period) Rst_n=1; #(`clock_period*20) $stop; end endmodule
生成的波形图为:
mealy型寄存器交换状态机如下,状态A仍为复位状态,只要w从0变为1,输出控制信号R2out,R3in就被置位。它们将保持置位直到下一个时钟周期电路离开状态A,进入状态B。在状态B中,不管w=0或是1,输出控制信号R1out,R2in都被置位,最后,在状态C中,通过R3out=1,R1in=1完成交换,并置位Done=1。与moore时钟电路相比,mealy型实现的信号输出要早一个时钟周期。因为有3个状态,所以也需要2个触发器。
如果采用独热码,则需要3个触发器。状态A,B,C分别取值为y3y2y1=001,y3y2y1=010,y3y2y1=100,类似moore型独热码信号输出公式,我们也可以得到mealy信号输出公式:
Y1=~wy1+y3
Y2=wy1
Y3=y2
R1out=R2in=y2
R1in=R3out=Done=y3
R2out=R3in=y1
mealy型的寄存器交换verilog代码为
module st_mealy(clk, Rst_n, w, R1in,R1out,R2in,R2out,R3in,R3out,Done); input clk; input Rst_n; input w; output reg R1in,R1out,R2in,R2out,R3in,R3out,Done; reg [1:0] y,Y; parameter [1:0] A=2'b00,B=2'b01,C=2'b10; //得到下一个状态的组合电路 always @(w,y) begin case(y) A: if(w) begin Y=B; R2out=1; R3in=1; R3out=0; R1in=0; Done=0; end else Y=A; B: begin Y=C; R2out=0; R3in=0; R1out=1; R2in=1; end C: begin Y=A; R1out=0; R2in=0; R3out=1; R1in=1; Done=1; end default: begin Y=2'bxx; R2out=1'bx; R3in=1'bx; R1out=1'bx; R2in=1'bx; R3out=1'bx; R1in=1'bx; Done=1'bx; end endcase end always @(posedge clk, negedge Rst_n) if(Rst_n==0) y<=A; else y<=Y; endmodule
testbench代码为
`timescale 1ns/1ns `define clock_period 20 module regswap_tb; reg clk=0; reg Rst_n; reg w; wire R1in,R1out,R2in,R2out,R3in,R3out,Done; st_mealy st_mealy0(.clk(clk),.Rst_n(Rst_n),.w(w),.R1in(R1in),.R1out(R1out),.R2in(R2in),.R2out(R2out),.R3in(R3in),.R3out(R3out),.Done(Done)); always #(`clock_period/2) clk=~clk; initial begin Rst_n=1; w=0; #(`clock_period) w=1; Rst_n=0; #(`clock_period) Rst_n=1; #(`clock_period*20) $stop; end