如果对速度要求不高,我们也可以使用串行加法器。下面通过状态机来实现串行加法器的功能。
设A=aa…a, B=bb…b,是要相加的两个无符号数,相加的和为:sum=ss…s。我们现在要设计一个电路,在时钟周期内处理一位相加的串行加法。加法过程一开始进行a,b的相加,在下一个时钟周期完成 a,b和第0位进位的相加,并依次完成所有的加法。
下图的方案中,3个移位寄存器用来保存A,B以及和Sum。假设这些寄存器有并行加载功能,先将加A,B的值载入这些寄存器,在时钟的每个周期,通过加法器FSM控制每位相加,在周期的最后把输出的结果移入Sum寄存器。我们使用上升沿触发的触发器,这样所有数据在时钟的上升沿及各个触发器的传播延迟后发生变化,此时三个移位寄存器内容右移:将加法结果移入Sum,并将下一对 a,b加载至加法器FSM。
下面是加法器FSM的图:
我们来设计状态机,假设有两个状态:状态G,进位为0,状态H,进位为1。则状态图如下,输出s取绝与当前状态(进位)和输入a,b的值,所以这是mealy型状态机。
在状态G中,输入00,则仍在状态G,输出为0,为01和10时候,仍在状态G,输出为1,如果输入为11,则转到状态H,输出0。
在状态H中,输入11,仍在状态H,输出1,输入为01和10时候,仍在状态H,输出为0,如果输入为00,则转到状态G,输出为1。
这个mealy型串行加法器的状态表如下:
根据状态表,利用卡诺图简化,有下列表达式,显然它就是全加器的输出表达式。
Y = ab+ay+by
s = a^b^y
现在状态 | 下一状态(ab) | 输出s | ||||||
00 | 01 | 10 | 11 | 00 | 01 | 10 | 11 | |
G | G | G | G | H | 0 | 1 | 1 | 0 |
H | G | H | G | G | 1 | 0 | 0 | 1 |
现在状态 | 下一状态(ab) | 输出(ab) | ||||||
00 | 01 | 11 | 10 | 00 | 01 | 11 | 10 | |
y | Y | s | ||||||
0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 |
1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
下面是verilog实现代码,首先是移位寄存器的代码,该移位寄存器带有使能输入E,E=1时,寄存器的内容将在时钟的上升沿开始从左到右。E=0,可以阻止移位寄存器内容发生改变。
module shiftrne(R,L,E,w,clk,Q); parameter n=8;
input [n-1:0] R;
input L,E,w,clk;
output reg [n-1:0] Q; integer k; always @(posedge clk) begin
if(L)
Q<=R;
else if(E) begin
for(k=n-1; k>0; k=k-1)
Q[k-1] <= Q[k];
Q[n-1] <=w;
end end endmodule
下面是mealy型串行加法的代码,代码中首先例化了三个移位寄存器。代码中还包括一个递减计数器,用来完成n位加法并输出至移位寄存器后,停止加法器。
代码中我们采用高电平复位信号。输出端的使能信号为Run信号,只要Run信号为1,递减计数器每个时钟周期都会递减。
module serialadd(A,B,Rst,clk,S);
input [7:0] A,B;
input Rst,clk;
output wire [7:0] S; reg [3:0] Count;
reg s,y,Y;
wire [7:0] QA,QB;
wire Run;
parameter G=1'b0, H=1'b1; shiftrne #(.n(8)) shift_A(.R(A),.L(Rst),.E(1'b1),.w(1'b0),.clk(clk),.Q(QA));
shiftrne #(.n(8)) shift_B(.R(B),.L(Rst),.E(1'b1),.w(1'b0),.clk(clk),.Q(QB));
shiftrne #(.n(8)) shift_S(.R(8'b0),.L(Rst),.E(Run),.w(s),.clk(clk),.Q(S)); //adder FSM
//output and next state cominatioal circuit always @(QA,QB,y) begin case (y)
G:
begin
s = QA[0]^QB[0];
if(QA[0]&QB[0]) Y=H;
else Y=G; end
H:
begin
s = QA[0]~^QB[0];
if(~QA[0]&~QB[0]) Y=G;
else Y=H; end
default:
Y = G;
endcase
end //sequential block
always @(posedge clk)
if(Rst)
y<=G;
else
y<=Y; //control shift proecess
always @(posedge clk)
if(Rst) Count=8;
else if(Run) Count = Count-1; assign Run = |Count;
endmodule
testbench代码为:
`timescale 1ns/1ns
`define clock_period 20 module serialadd_tb;
reg clk;
reg Rst; reg [7:0] A,B;
wire [7:0] S; serialadd serialadd0(.A(A),.B(B),.Rst(Rst),.clk(clk),.S(S));
//serialadd_moore serialadd_moore0(.A(A),.B(B),.Rst(Rst),.clk(clk),.S(S));
always #(`clock_period/2) clk = ~clk; initial begin
clk=0;
A = 8'd35;
B = 8'd99;
Rst = 0;
#(`clock_period)
Rst = 1;
#(`clock_period)
Rst = 0; #(`clock_period*10) $stop; end endmodule
下面是mealy型串行加法的波形,输入35,99,输出134
我们把状态图做如下调整,拆分G为G0,G1,拆分H为H0,H1, 则输出之和状态有关,为moore型串行加法器状态图。
下面是该状态机的状态表:
现在状态 | 下一状态(ab) | 输出 | |||
00 | 01 | 10 | 11 | s | |
G0 | G0 | G1 | G1 | H0 | 0 |
G1 | G0 | G1 | G1 | H0 | 1 |
H0 | G1 | H0 | H0 | H1 | 0 |
H1 | G1 | H0 | H0 | H1 | 1 |
现在状态 | 下一状态(ab) | 输出 | |||
00 | 01 | 10 | 11 | s | |
y2y1 | Y2Y1 | ||||
00 | 00 | 01 | 01 | 10 | 0 |
01 | 00 | 01 | 01 | 10 | 1 |
10 | 01 | 10 | 10 | 11 | 0 |
11 | 01 | 10 | 10 | 11 | 1 |
可以推导出
Y=a^b^y
Y=ab+ay2+by
s=y
下面是其可能的实现电路。moore型加法输出比mealy型加法多了一个时钟周期的时延。
moore型串行加法器verilog代码如下,其中也例化了3个移位寄存器。注意Count复位后为9,
module serialadd_moore(A,B,Rst,clk,S);
input [7:0] A,B;
input Rst,clk;
output wire [7:0] S; reg [3:0] Count;
reg [1:0] y,Y;
wire [7:0] QA,QB;
wire s,Run;
parameter G0=2'b00, G1=2'b01,H0=2'b10, H1=2'b11; shiftrne #(.n(8)) shift_A(.R(A),.L(Rst),.E(1'b1),.w(1'b0),.clk(clk),.Q(QA));
shiftrne #(.n(8)) shift_B(.R(B),.L(Rst),.E(1'b1),.w(1'b0),.clk(clk),.Q(QB));
shiftrne #(.n(8)) shift_S(.R(8'b0),.L(Rst),.E(Run),.w(s),.clk(clk),.Q(S)); //adder FSM
//output and next state cominatioal circuit always @(QA,QB,y) begin case (y)
G0:
begin
if(QA[0]&QB[0]) Y=H0;
else if(~QA[0]&~QB[0]) Y=G0;
else Y=G1; end
G1:
begin
if(~QA[0]&~QB[0]) Y=G0;
else if (QA[0]&QB[0])Y=H0;
else Y=G1; end
H0:
begin
if(QA[0]&QB[0]) Y=H1;
else if(~QA[0]&~QB[0]) Y=G1;
else Y=H0; end
H1:
begin
if(~QA[0]&~QB[0]) Y=G1;
else if (QA[0]&QB[0])Y=H1;
else Y=H0; end
endcase
end //sequential block
always @(posedge clk)
if(Rst)
y<=G0;
else
y<=Y; //control shift proecess
always @(posedge clk)
if(Rst) Count=9;
else if(Run) Count = Count-1; assign Run = |Count;
assign s = (y==H0?1'b0:(y==G0?1'b0:1'b1));
endmodule
`timescale 1ns/1ns
`define clock_period 20 module serialadd_tb;
reg clk;
reg Rst; reg [7:0] A,B;
wire [7:0] S; //serialadd serialadd0(.A(A),.B(B),.Rst(Rst),.clk(clk),.S(S));
serialadd_moore serialadd_moore0(.A(A),.B(B),.Rst(Rst),.clk(clk),.S(S));
always #(`clock_period/2) clk = ~clk; initial begin
clk=0;
A = 8'd35;
B = 8'd99;
Rst = 0;
#(`clock_period)
Rst = 1;
#(`clock_period)
Rst = 0; #(`clock_period*10) $stop; end endmodule
输出波形为: