1. 程式人生 > >Wallace樹形乘法器,自動生成器(C/C++版)

Wallace樹形乘法器,自動生成器(C/C++版)

學過《數字邏輯》課程的同學,對於Wallace樹形乘法器應該不陌生(手拙,靈魂畫師……建議讀者參考網上的圖片)。

總的來說,就是一個無符號數乘法器。特點是速度快,使用邏輯電路完成乘法,但是佔用的資源也比較多(對於位數比較多的乘法而言)。

之前在學習李亞明老師寫的書《計算機原理與設計——Verilog HDL版》時,由於其中用到了26x26的Wallace乘法器,分析了該乘法器的特點,並按照自己的思路利用C/C++語言編寫了一下Wallace乘法器的生成器(設定好幾位乘幾位的引數後,生成可以執行的Verilog程式碼)。

生成器的關鍵在於,將項()放到合適的一位全加器的一個輸入上。全加器的當前輸出位仍然在當前列,但是進位應該放到下一層的前一列全加器的輸入中。

下面是6x4的Wallace程式碼(其中add1表示一位全加器,s表示加法結果,c表示進位):

module wallace_tree6x4(
		input  [5:0] a,
		input  [3:0] b,
		//output [5:0] sum,
		//output [6:0] carry,
		//output [2:0] z3,
		output [9:0] z
	);

	wire zero = 1'b0;
	reg [3:0] p[5:0];

	integer i, j;
	always @*
	begin
		for(i=0; i<6; i=i+1)
			for(j=0; j<4; j=j+1)
				p[i][j] = a[i] & b[j];
	end

//level 1
	wire [1:0] s1[10:00];
	wire [1:0] c1[10:00];
	//	p[05][03]
	add1 fa01_07_00 (p [04][03], p [05][02], zero      , s1[07][00], c1[08][00]);
	add1 fa01_06_00 (p [03][03], p [04][02], p [05][01], s1[06][00], c1[07][00]);
	add1 fa01_05_00 (p [02][03], p [03][02], p [04][01], s1[05][00], c1[06][00]);
	//	p[05][00]
	add1 fa01_04_00 (p [01][03], p [02][02], p [03][01], s1[04][00], c1[05][00]);
	//	p[04][00]
	add1 fa01_03_00 (p [00][03], p [01][02], p [02][01], s1[03][00], c1[04][00]);
	//	p[03][00]
	add1 fa01_02_00 (p [00][02], p [01][01], p [02][00], s1[02][00], c1[03][00]);
	add1 fa01_01_00 (p [00][01], p [01][00], zero      , s1[01][00], c1[02][00]);
	//	p[00][00]

//level 2
	wire [10:00] s2;
	wire [10:00] c2;
	add1 fa02_08_00 (p [05][03], c1[08][00], zero      , s2[08], c2[09]);
	add1 fa02_07_00 (s1[07][00], c1[07][00], zero      , s2[07], c2[08]);
	add1 fa02_06_00 (s1[06][00], c1[06][00], zero      , s2[06], c2[07]);
	add1 fa02_05_00 (p [05][00], s1[05][00], c1[05][00], s2[05], c2[06]);
	add1 fa02_04_00 (p [04][00], s1[04][00], c1[04][00], s2[04], c2[05]);
	add1 fa02_03_00 (p [03][00], s1[03][00], c1[03][00], s2[03], c2[04]);
	add1 fa02_02_00 (s1[02][00], c1[02][00], zero      , s2[02], c2[03]);
	//	s1[01][00]
	//	p[00][00]

	assign z[2] = s2[02];
	assign z[1] = s1[01][00];
	assign z[0] = p [00][00];
	//assign z3 = z[2:0];
	//assign sum = s2[08:03];
	//assign carry = {s2[09]|c2[09], c2[08:03]};
	assign z[09:03] = s2[09:03] + c2[09:03];

endmodule

以下是64x64位的Wallace乘法器的模擬結果:

我的計算機自帶計算器只能進行32x32的乘法,沒有嘗試用其他語言模擬大數運算(感覺應該不會有錯)。

以下是程式碼生成器程式碼:


/* 其中引數有N和M,LEVEL三個巨集定義了的引數
 * N和M表示乘法器位數為N*M的乘法器
 * 其中LEVEL需要根據設定的N和M測試,例如(N,M,LEVEL)有(24,24,7),(8,8,4)
 * 生成的程式碼在檔名:test1.txt
 * 生成的模組的主要輸入有:a[N-1:0], b[M-1:0];
 *            主要輸出有:z[N+M-1:0];
 */


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

#define N 6
#define M 4
#define LEVEL 2

int p[N+M][N+M];
int s[LEVEL+1][N+M][N+M];
int c[LEVEL+1][N+M][N+M];

char w[3];
int  a[3];
int  b[3];
int  t[3];

char functionName[] = "add1";

void init();
void clean(char w, int a, int b, int c);
void print(int f, int sum, int n, int l);
int fill_w_a_b(int sum, int l);
void sub_P_wab(char w, int a, int b, int c);
void getend();


int main()
{
    freopen("test1.txt", "w", stdout);
    init();
    int T = LEVEL;
    int l = 1;
    int L = max(N, M);
    while(T--){
        cout<<"//level "<<l<<endl;
        if(T > 0){
            printf("\twire [%d:0] s%d[%2d:00];\n", (L-2)/3, l, N+M);
            printf("\twire [%d:0] c%d[%2d:00];\n", (L-2)/3, l, N+M);
        }
        else{
            printf("\twire [%2d:00] s%d;\n", N+M, l);
            printf("\twire [%2d:00] c%d;\n", N+M, l);
        }
        for(int i=N+M; i>=0; i--){
            int n = 0;
            int sum = i;
            //cout<<sum<<endl;
            while(1){
                int num = 0;
                num = fill_w_a_b(sum, l);
                print(num, sum, n++, l);
                if(num <= 1)
                    break;
            }
        }
        cout<<endl;
        l++;
    }
    getend();
    return 0;
}


int fill_w_a_b(int sum, int l)
{
    int n = 0;
    for(int i=0; i<N+M && n<3; i++){
        for(int j=0; j<N+M && n<3; j++){
            if((i+j)==sum && p[i][j]){
                w[n] = 'p';
                a[n] = i;
                b[n] = j;
                t[n] = -1;
                n++;
            }
        }
    }
    for(int z=0; z<LEVEL; z++){
        for(int i=0; i<N+M && n<3; i++){
            for(int j=0; j<N+M && n<3; j++){
                if(i==sum && z<l && s[z][i][j]){
                    w[n] = 's';
                    a[n] = i;
                    b[n] = j;
                    t[n] = z;
                    if(z == 0)
                        cout<<"???????1111"<<endl;
                    n++;
                }
            }
        }
    }
    for(int z=0; z<LEVEL; z++){
        for(int i=0; i<N+M && n<3; i++){
            for(int j=0; j<N+M && n<3; j++){
                if(i==sum && z<l && c[z][i][j]){
                    w[n] = 'c';
                    a[n] = i;
                    b[n] = j;
                    t[n] = z;
                    if(z == 0)
                        cout<<"???????2222"<<endl;
                    n++;
                }
            }
        }
    }
    return n;
}

void print(int f, int sum, int n, int l)
{
    if(f == 3){
        printf("\t");
        printf("%s ", functionName);
        printf("fa%02d_%02d_%02d ", l, sum, n);
        printf("(");

        sub_P_wab(w[0], a[0], b[0], t[0]);
        sub_P_wab(w[1], a[1], b[1], t[1]);
        sub_P_wab(w[2], a[2], b[2], t[2]);

        if(l != LEVEL)
            printf("s%d[%02d][%02d], ", l, sum, n);
        else
            printf("s%d[%02d], ", l, sum);
        s[l][sum][n] = 1;

        if(l != LEVEL)
            printf("c%d[%02d][%02d]", l, sum+1, n);
        else
            printf("c%d[%02d]", l, sum+1);
        c[l][sum+1][n] = 1;

        printf(");\n");
    }
    else if(f == 2){
        printf("\t");
        printf("%s ", functionName);
        printf("fa%02d_%02d_%02d ", l, sum, n);
        printf("(");

        sub_P_wab(w[0], a[0], b[0], t[0]);
        sub_P_wab(w[1], a[1], b[1], t[1]);
        printf("zero      , ");

        if(l != LEVEL)
            printf("s%d[%02d][%02d], ", l, sum, n);
        else
            printf("s%d[%02d], ", l, sum);
        s[l][sum][n] = 1;

        if(l != LEVEL)
            printf("c%d[%02d][%02d]", l, sum+1, n);
        else
            printf("c%d[%02d]", l, sum+1);
        c[l][sum+1][n] = 1;

        printf(");\n");
    }
    else if(f == 1){
        if(w[0]=='s' || w[0]=='c'){
            if(t[0] != 0)
                printf("\t//\t%c%d[%02d][%02d]\n", w[0], t[0], a[0], b[0]);
        }
        else
            printf("\t//\t%c[%02d][%02d]\n", w[0], a[0], b[0]);
    }
}

void sub_P_wab(char w, int a, int b, int c)
{
    if(w == 'p'){
        printf("%-2c[%02d][%02d], ", w, a, b);
        clean(w, a, b, c);
    }
    else if(w == 's' || w == 'c'){
        printf("%c%d[%02d][%02d], ", w, c, a, b);
        clean(w, a, b, c);
    }
}

void clean(char w, int a, int b, int t)
{
    switch(w){
        case 'p' : p[a][b] = 0; break;
        case 's' : s[t][a][b] = 0; break;
        case 'c' : c[t][a][b] = 0; break;
        default : break;
    }
}

void init()
{
    memset(p, 0, sizeof(p));
    memset(s, 0, sizeof(p));
    memset(c, 0, sizeof(p));
    for(int i=0; i<N; i++)
        for(int j=0; j<M; j++)
            p[i][j] = 1;
    printf("module wallace_tree%dx%d(\n", N, M);
    printf("\t\tinput  [%d:0] a,\n", N-1);
    printf("\t\tinput  [%d:0] b,\n", M-1);
    printf("\t\t//output [%d:0] sum,\n", N+M-LEVEL-3);
    printf("\t\t//output [%d:0] carry,\n", N+M-LEVEL-2);
    printf("\t\t//output [%d:0] z%d,\n", LEVEL, LEVEL+1);
    printf("\t\toutput [%d:0] z\n", N+M-1);
    printf("\t);\n\n");

    printf("\twire zero = 1\'b0;\n");
    printf("\treg [%d:0] p[%d:0];\n\n", M-1, N-1);

    printf("\tinteger i, j;\n");
    printf("\talways @*\n");
    printf("\tbegin\n");
    printf("\t\tfor(i=0; i<%d; i=i+1)\n", N);
    printf("\t\t\tfor(j=0; j<%d; j=j+1)\n", M);
    printf("\t\t\t\tp[i][j] = a[i] & b[j];\n");
    printf("\tend\n\n");
}

void getend()
{
    printf("\tassign z[%d] = s%d[%02d];\n", LEVEL, LEVEL, LEVEL);
    for(int i=LEVEL-1; i>0; i--){
        printf("\tassign z[%d] = s%d[%02d][00];\n", i, i, i);
    }
    printf("\tassign z[0] = p [00][00];\n");

    printf("\t//assign z%d = z[%d:0];\n", LEVEL+1, LEVEL);
    printf("\t//assign sum = s%d[%02d:%02d];\n", LEVEL, N+M-2, LEVEL+1);
    printf("\t//assign carry = {s%d[%02d]|c%d[%02d], c%d[%02d:%02d]};\n", LEVEL, N+M-1, LEVEL, N+M-1, LEVEL, N+M-2, LEVEL+1);
    printf("\tassign z[%02d:%02d] = s%d[%02d:%02d] + c%d[%02d:%02d];\n\n",
                        N+M-1, LEVEL+1, LEVEL, N+M-1, LEVEL+1, LEVEL, N+M-1, LEVEL+1);

    printf("endmodule\n");
}

有疑問或者有問題或者想要提意見的讀者,可以給我留言哈!