Wallace樹形乘法器,自動生成器(C/C++版)
阿新 • • 發佈:2018-12-14
學過《數字邏輯》課程的同學,對於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"); }
有疑問或者有問題或者想要提意見的讀者,可以給我留言哈!