思路,A,B相乘,A每个时钟周期左移,B每个时钟周期右移,用B0判断是否相加。
整个模块包括的端口信号:时钟、复位、载入数据A及载入信号LA,载入数据B及载入信号B,开始计算信号s,输出数据P,完成信号done。
数据流:(1)一个2n位宽的移位寄存器,用于A左移,一个n位宽的右移寄存器,用于B右移。
(由于进入状态S2后才会发出移位信号,移位是在状态S2之后,状态S2的第一个时钟周期会自动计算第一位的结果)
(2)将A左移后的结果和之前的结果相加得出结果,并且由此时的B0决定是否载入到寄存器中,若为1则载入新结果,否则保持原结果
(3)当计算完成后,判断出Bs为0,跳转到S3状态,发出done信号,再由done信号使P归零。
1 移位加乘法器顶层模块
`timescale 1ns/1ps
module ShiftProduct(Clk,Rst_n,A,B,s,P,Done,La,Lb);
input Clk,Rst_n;
input [7:0] A,B;
input s;
output Done;
output reg [15:0] P;
wire z;
wire [7:0] Bs;
wire [15:0] As;
input wire La,Lb;
wire Ea,Eb;
//wire Psel;
wire [15:0] Sum,DataP;
wire EP;
parameter S1=2'b00,S2=2'b01,S3=2'b10;
reg [1:0] state,next_state;
assign z= ~|Bs;
assign Ea = state==S2;
assign Eb = state==S2;
//assign Psel = state==S2;
assign Done = state==S3;
assign EP= state==S2 &(Bs[0]) ;
always@(*) begin
case(state)
S1:
if (s) next_state = S2;
else next_state = S1;
S2:
if(z) next_state = S3;
else next_state =S2;
S3:
if(s) next_state =S3;
else next_state = S1;
default: next_state = S1;
endcase
end
always@(posedge Clk ,negedge Rst_n) begin
state <= Rst_n?next_state:S1;
end
/*always@(*) begin
case(state)
S1: Sum = 0;
S2: if(Bs[0]) Sum = P + As;
S3: Sum = As + P;
default:Sum = 0;
endcase
end*/
assign Sum = P + As ; //虽然一直在计算得到sum,并且状态S2中,Psel一直为1,选通sum输入到datap,但是由于B0=0时,Ep=0,计算得到的sum传到datap后不会寄存到P寄存器。下一个周期,sum会重新计算,并且此时的P还是之前的P,此时的As再次更新。
assign DataP = Sum;// Psel?Sum:0;
always@(posedge Clk or negedge Rst_n) begin
if(~Rst_n)
P <= 0;
else if(EP)
P <= DataP;
else if(Done)
P <= 0;
end
shiftlne shiftA(.Clk(Clk),.Data({{8'b0},A}),.La(La),.Ea(Ea),.w(1'b0),.A(As));
defparam shiftA.n = 16;
shiftrne shiftB(.Clk(Clk),.Data(B),.La(Lb),.Ea(Eb),.w(1'b0),.A(Bs));
endmodule
2 左移位和右移模块
`timescale 1ns/1ps
module shiftlne (Clk,Data,A,La,Ea,w);
parameter n = 8;
input Clk,w;
input [n-1:0] Data;
output reg [n-1:0] A;
input La,Ea;
always@(posedge Clk ) begin
if(La)
A <= Data;
else if (Ea)
A <= {A[14:0],w};
end
endmodule
`timescale 1ns/1ps
module shiftrne(Clk,Data,La,Ea,A,w);
parameter n = 8;
input Clk,La,Ea,w;
input [n-1:0] Data;
output reg [n-1:0] A;
always @(posedge Clk) begin
if(La)
A <= Data;
else if (Ea)
A <= {w,A[7:1]};
end
endmodule
3 测试模块
`timescale 1ns/1ps
`define clk_period 20
module tb_SP();
reg clk,rst_n,s,la,lb;
reg [7:0] a,b;
wire [15:0] p;
wire done;
ShiftProduct Sp0(.Clk(clk),.Rst_n(rst_n),.A(a),.B(b),.La(la),.Lb(lb),.s(s),.P(p),.Done(done));
initial clk = 1'b1;
always #(`clk_period /2) clk = ~clk;
initial begin
rst_n = 0 ; la=0;
s = 0 ;
a = 8'd0; b=8'd0;
# (5*`clk_period/2) rst_n =1;
# 20;a=8'b00000001;la=1;lb=1;b=8'b00000010;
#20;a=8'd0;b=8'b0;la=0;lb=0;
s=1;
#(8*`clk_period);
s=0;
#100;
# 20;a=8'b00011001;la=1;lb=1;b=8'b11000010;
#20;a=8'd0;b=8'b0;la=0;lb=0;
s=1;
#(8*`clk_period);
s=0;
#100;
# 20;a=8'b01100000;la=1;lb=1;b=8'b00000110;
#20;a=8'd0;b=8'b0;la=0;lb=0;
s=1;
#(8*`clk_period);
s=0;
#100;
end
initial
begin
$fsdbDumpfile("ShiftP.fsdb");
$fsdbDumpvars;
$fsdbDumpon;
end
initial #5000 $finish;
endmodule