本文的知识来源于华中科技大学,谭志虎教授的计算机硬件系统设计,向他致敬
https://www.icourse163.org/course/HUST-1205809816?tid=1467135471
横向进位阵列乘法器
module lateral_carry_array_multiplier (
input [4:0] in1,
input [4:0] in2,
output [9:0]product
);
wire [4:0] a0;
assign a0 = {5{in2[0]}}&in1; //in2[0]?in1:0;
wire [4:0] a1;
assign a1 = {5{in2[1]}}&in1;
wire [4:0] a2;
assign a2 = {5{in2[2]}}&in1;
wire [4:0] a3;
assign a3 = {5{in2[3]}}&in1;
wire [4:0] a4;
assign a4 = {5{in2[4]}}&in1;
wire [4:0] cout1;
wire [4:0] sum1;
full_adder u10 ( .in1 ( a0[1] ), .in2 ( a1[0] ), .cin ( 0 ), .sum ( sum1[0] ), .cout( cout1[0]) );
full_adder u11 ( .in1 ( a0[2] ), .in2 ( a1[1] ), .cin ( cout1[0] ), .sum ( sum1[1] ), .cout( cout1[1]) );
full_adder u12 ( .in1 ( a0[3] ), .in2 ( a1[2] ), .cin ( cout1[1] ), .sum ( sum1[2] ), .cout( cout1[2]) );
full_adder u13 ( .in1 ( a0[4] ), .in2 ( a1[3] ), .cin ( cout1[2] ), .sum ( sum1[3] ), .cout( cout1[3]) );
full_adder u14 ( .in1 ( 0 ), .in2 ( a1[4] ), .cin ( cout1[3] ), .sum ( sum1[4] ), .cout( cout1[4]) );
wire [4:0] cout2;
wire [4:0] sum2;
full_adder u20 ( .in1 ( sum1[1] ), .in2 ( a2[0] ), .cin ( 0 ), .sum ( sum2[0] ), .cout( cout2[0]) );
full_adder u21 ( .in1 ( sum1[2] ), .in2 ( a2[1] ), .cin ( cout2[0] ), .sum ( sum2[1] ), .cout( cout2[1]) );
full_adder u22 ( .in1 ( sum1[3] ), .in2 ( a2[2] ), .cin ( cout2[1] ), .sum ( sum2[2] ), .cout( cout2[2]) );
full_adder u23 ( .in1 ( sum1[4] ), .in2 ( a2[3] ), .cin ( cout2[2] ), .sum ( sum2[3] ), .cout( cout2[3]) );
full_adder u24 ( .in1 ( cout1[4] ), .in2 ( a2[4] ), .cin ( cout2[3] ), .sum ( sum2[4] ), .cout( cout2[4]) );
wire [4:0] cout3;
wire [4:0] sum3;
full_adder u30 ( .in1 ( sum2[1] ), .in2 ( a3[0] ), .cin ( 0 ), .sum ( sum3[0] ), .cout( cout3[0]) );
full_adder u31 ( .in1 ( sum2[2] ), .in2 ( a3[1] ), .cin ( cout3[0] ), .sum ( sum3[1] ), .cout( cout3[1]) );
full_adder u32 ( .in1 ( sum2[3] ), .in2 ( a3[2] ), .cin ( cout3[1] ), .sum ( sum3[2] ), .cout( cout3[2]) );
full_adder u33 ( .in1 ( sum2[4] ), .in2 ( a3[3] ), .cin ( cout3[2] ), .sum ( sum3[3] ), .cout( cout3[3]) );
full_adder u34 ( .in1 ( cout2[4] ), .in2 ( a3[4] ), .cin ( cout3[3] ), .sum ( sum3[4] ), .cout( cout3[4]) );
wire [4:0] cout4;
wire [4:0] sum4;
full_adder u40 ( .in1 ( sum3[1] ), .in2 ( a4[0] ), .cin ( 0 ), .sum ( sum4[0] ), .cout( cout4[0]) );
full_adder u41 ( .in1 ( sum3[2] ), .in2 ( a4[1] ), .cin ( cout4[0] ), .sum ( sum4[1] ), .cout( cout4[1]) );
full_adder u42 ( .in1 ( sum3[3] ), .in2 ( a4[2] ), .cin ( cout4[1] ), .sum ( sum4[2] ), .cout( cout4[2]) );
full_adder u43 ( .in1 ( sum3[4] ), .in2 ( a4[3] ), .cin ( cout4[2] ), .sum ( sum4[3] ), .cout( cout4[3]) );
full_adder u44 ( .in1 ( cout3[4] ), .in2 ( a4[4] ), .cin ( cout4[3] ), .sum ( sum4[4] ), .cout( cout4[4]) );
assign product = {cout4[4], sum4, sum3[0], sum2[0], sum1[0], a0[0]};
endmodule
module full_adder (
input in1,
input in2,
input cin,
output sum,
output cout
);
wire xor2;
assign xor2 = in1^ in2; // reuse
assign sum = xor2^ cin;
// assign cout = in1&in2| in1&cin| in2&cin; // 3and 2or
// assign cout = in1&in2| cin&(in1|in2); // one less and, 2and 2or
assign cout = (xor2&cin) | (in1&in2); // resuse in1^in2, 2and 1or
endmodule
流水线横向进位阵列乘法器
module real_papeline_lateral_carry_array_multiplier (
input clk,
input rst_n,
input [4:0] in1,
input [4:0] in2,
output [9:0]product
);
wire [4:0] a0;
assign a0 = {5{in2[0]}}&in1;
wire [4:0] a1;
assign a1 = {5{in2[1]}}&in1;
wire [4:0] a2;
assign a2 = {5{in2[2]}}&in1;
wire [4:0] a3;
assign a3 = {5{in2[3]}}&in1;
wire [4:0] a4;
assign a4 = {5{in2[4]}}&in1;
wire [4:0] a00;
wire [5:0] a11;
wire [6:0] a22;
wire [7:0] a33;
wire [8:0] a44;
assign a00 = a0<<0;
assign a11 = a1<<1;
assign a22 = a2<<2;
assign a33 = a3<<3;
assign a44 = a4<<4;
wire [6:0] b11;
wire [7:0] b22;
wire [8:0] b33;
wire [9:0] b44;
serial_carry_adder #(
.WIDTH ( 6 ))
u1 (
.in1 ( {1'b0, a00} ),
.in2 ( a11 ),
.cin ( 1'b0 ),
.sum ( b11 )
);
reg [6:0] pro1;
reg [6:0] a22_r;
reg [7:0] a33_r;
reg [8:0] a44_r;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
pro1 <= 7'd0;
a22_r <= 7'd0;
a33_r <= 8'd0;
a44_r <= 9'd0;
end
else begin
pro1 <= b11;
a22_r <= a22;
a33_r <= a33;
a44_r <= a44;
end
serial_carry_adder #(
.WIDTH ( 7 ))
u2 (
.in1 ( pro1 ),
.in2 ( a22_r ),
.cin ( 1'b0 ),
.sum ( b22 )
);
reg [7:0] pro2;
reg [7:0] a33_r_r;
reg [8:0] a44_r_r;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
pro2 <= 8'd0;
a33_r_r <= 8'd0;
a44_r_r <= 9'd0;
end
else begin
pro2 <= b22;
a33_r_r <= a33_r;
a44_r_r <= a44_r;
end
serial_carry_adder #(
.WIDTH ( 8 ))
u3 (
.in1 ( pro2 ),
.in2 ( a33_r_r ),
.cin ( 1'b0 ),
.sum ( b33 )
);
reg [8:0] pro3;
reg [8:0] a44_r_r_r;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
pro3 <= 9'd0;
a44_r_r_r <= 9'd0;
end
else begin
pro3 <= b33;
a44_r_r_r <= a44_r_r;
end
serial_carry_adder #(
.WIDTH ( 9 ))
u4 (
.in1 ( pro3 ),
.in2 ( a44_r_r_r ),
.cin ( 1'b0 ),
.sum ( b44 )
);
reg [9:0] pro4;
always@(posedge clk or negedge rst_n)
if(!rst_n)
pro4 <= 10'd0;
else
pro4 <= b44;
assign product = pro4;
endmodule
module serial_carry_adder#(
parameter WIDTH = 8
)(
input [WIDTH-1:0] in1,
input [WIDTH-1:0] in2,
input cin,
output [WIDTH:0] sum
);
wire [WIDTH:0]cout;
assign cout[0] = cin;
genvar i;
generate
for(i=0; i<WIDTH; i=i+1)
begin :gf
full_adder ufa(
.in1 (in1[i]),
.in2 (in2[i]),
.cin (cout[i]),
.sum (sum[i]),
.cout (cout[i+1])
);
end
endgenerate
assign sum[WIDTH] = cout[WIDTH];
endmodule
TB
`timescale 1ns / 1ps
module tb_papeline_lateral_carry_array_multiplier;
// papeline_lateral_carry_array_multiplier Parameters
parameter PERIOD = 10;
// papeline_lateral_carry_array_multiplier Inputs
reg clk = 0 ;
reg rst_n = 0 ;
reg [4:0] in1 = 0 ;
reg [4:0] in2 = 0 ;
// papeline_lateral_carry_array_multiplier Outputs
wire [9:0] product ;
initial
begin
forever #(PERIOD/2) clk=~clk;
end
initial
begin
#(PERIOD*2) rst_n = 1;
@(posedge clk)
in1 = 2;
in2 = 4;
@(posedge clk)
in1 = 3;
in2 = 5;
@(posedge clk)
in1 = 8;
in2 = 16;
@(posedge clk)
in1 = 9;
in2 = 17;
@(posedge clk)
in1 = 31;
in2 = 31;
@(posedge clk)
in1 = 30;
in2 = 29;
@(posedge clk)
in1 = 0;
in2 = 31;
@(posedge clk)
in1 = 31;
in2 = 0;
@(posedge clk)
in1 = 16;
in2 = 16;
@(posedge clk)
in1 = 31;
in2 = 15;
@(posedge clk);
end
real_papeline_lateral_carry_array_multiplier u1 (
.clk ( clk ),
.rst_n ( rst_n ),
.in1 ( in1 [4:0] ),
.in2 ( in2 [4:0] ),
.product ( product [9:0] )
);
// initial
// begin
// $finish;
// end
endmodule
总结
不知道这样的流水线写法是不是对的,我没有想到更好的办法。
但是,这种流水线的写法,还能被叫做横向进位吗,我很迷茫。
似乎是的,因为每一行的对应元素相加,进位都是给了高位。
但是这样的流水线写法真的是对的吗?写法优美吗?