Результат сравнения различных методов построения модулярных умножителей (индексный метод, разность квадратов, метод Espresso)
Было проведено сравнение модулярных умножителей. Рассматриваемые методы:
- Метод минимизации логических функций на базе алгоритма Espresso
- Метод разности квадратов
- Индексная реализация умножителя
Метод Espresso заключается в построении таблицы истинности для операции модулярного умножения, и дальнейшей минимизации получившейся булевой функции методом Espresso. Сравнение проводилось для расширенного набора оснований в диапазоне 3-149. Индексный метод работает только для простых чисел, метод, основанный на разности квадратов допускает любые нечетные числа, а метод Espresso работает для любых целых чисел. Маршрут проектирования для схем Espresso включал минимизацию булевых функций с помощью программного средства Logic Friday. Для автоматизации запуска Logic Friday использовался язык автоматизации AutoIt. Для остальных двух схем использовался стандартный подход с реализацией автоматизироанных генераторов.
Содержание
Типовые Verilog-модули
1. Индексный модулярный умножитель (на примере модуля 7) [Показать]
2. Модулярный умножитель на базе формулы разности квадратов (на примере модуля 7)
module multiplication_mod_7(inp1, inp2, out);
input [2:0] inp1;
input [2:0] inp2;
output [2:0] out;
wire [3:0] plus;
wire [3:0] minus;
wire [2:0] plout;
wire [2:0] miout;
assign plus = inp1 + inp2; // [0; 12]
assign minus = 6 + inp1 - inp2; // [0; 12]
lut_sqr_sum ls1(plus, plout);
lut_sqr_sub ls2(minus, miout);
sub_mod_7 sub1(plout, miout, out);
endmodule
module lut_sqr_sum (in, out);
input [3:0] in;
output reg [2:0] out;
always @ (in)
begin
case (in)
0: out = 0;
1: out = 2;
2: out = 1;
3: out = 4;
4: out = 4;
5: out = 1;
6: out = 2;
7: out = 0;
8: out = 2;
9: out = 1;
10: out = 4;
11: out = 4;
12: out = 1;
default: out = 0;
endcase
end
endmodule
module lut_sqr_sub (in, out);
input [3:0] in;
output reg [2:0] out;
always @ (in)
begin
case (in)
0: out = 2;
1: out = 1;
2: out = 4;
3: out = 4;
4: out = 1;
5: out = 2;
6: out = 0;
7: out = 2;
8: out = 1;
9: out = 4;
10: out = 4;
11: out = 1;
12: out = 2;
default: out = 0;
endcase
end
endmodule
module sub_mod_7 (in1, in2, out);
input [2:0] in1, in2;
output [2:0] out;
wire [3:0] data;
assign data = 7 + in1 - in2;
mod_7_13 mdval(data, out);
endmodule
module mod_7_13 (in, out);
input [3:0] in;
output reg [2:0] out;
always @ (in)
begin
// we have small max value so we can use table here
case (in)
0: out = 0;
1: out = 1;
2: out = 2;
3: out = 3;
4: out = 4;
5: out = 5;
6: out = 6;
7: out = 0;
8: out = 1;
9: out = 2;
10: out = 3;
11: out = 4;
12: out = 5;
13: out = 6;
default: out = 0;
endcase
end
endmodule
module atop_testbench();
reg [2:0] inp1;
reg [2:0] inp2;
wire [2:0] out;
integer i, j, l, m, k, t;
reg dummy;
integer fori, forj;
multiplication_mod_7 mul1(inp1, inp2, out);
initial
begin
k = 1;
for (fori = 0; fori < 7; fori = fori + 1)
begin
for (forj = 0; forj < 7; forj = forj + 1)
begin
inp1 = fori;
inp2 = forj;
#1 dummy = 1;
i = (fori*forj)%7;
$display ("!!! OP1 = (%d) OP2 = (%d) RES = (%d) EXPECT = (%d)", fori, forj, out, i);
l = out;
if (l != i)
begin
$display ("!!! Error (%d, %d)!!!", i, l);
end
#1 dummy = 1;
end
end
end
endmodule
2. Модулярный сумматор по методу Espresso (на примере модуля 10)
module mul_mod10 (out, a, b); input [3:0] a, b; output [3:0] out; assign out[3] = (~a[3]&~a[2]&~a[1]&a[0]&b[3]) | (~a[2]&a[1]&~a[0]&b[3]&b[0]) | (a[3]&~b[3]&~b[2]&~b[1]&b[0]) | (a[2]&a[1]&~a[0]&b[3]&~b[0]) | (a[3]&~a[0]&b[2]&b[1]&~b[0]) | (a[3]&a[0]&~b[2]&b[1]&~b[0]) | (a[2]&a[1]&a[0]&b[2]&b[1]&b[0]) | (a[2]&~a[1]&~a[0]&b[2]&b[1]&b[0]) | (~a[2]&a[1]&a[0]&~b[2]&b[1]&b[0]) | (a[2]&a[1]&~a[0]&~b[2]&b[1]&b[0]) | (~a[2]&a[1]&a[0]&b[2]&b[1]&~b[0]) | (a[2]&~a[1]&~a[0]&~b[2]&b[1]&~b[0]) | (a[2]&a[1]&a[0]&b[2]&~b[1]&~b[0]) | (~a[2]&a[1]&~a[0]&b[2]&~b[1]&~b[0]); assign out[2] = (~a[2]&a[1]&a[0]&b[3]) | (a[3]&~a[0]&~b[2]&b[1]) | (a[2]&~a[1]&a[0]&b[0]) | (a[3]&~a[0]&b[1]&b[0]) | (a[3]&~b[2]&b[1]&b[0]) | (a[0]&b[2]&~b[1]&b[0]) | (~a[2]&a[1]&b[3]&~b[0]) | (a[1]&a[0]&b[3]&~b[0]) | (a[3]&~a[0]&b[3]&~b[0]) | (a[2]&~a[0]&b[2]&~b[0]) | (~a[2]&a[1]&~a[0]&b[1]&b[0]) | (a[1]&a[0]&~b[2]&b[1]&~b[0]) | (~a[3]&~a[2]&~a[1]&a[0]&b[2]) | (a[2]&~a[0]&~b[2]&~b[1]&b[0]) | (a[2]&~b[3]&~b[2]&~b[1]&b[0]) | (~a[2]&~a[1]&a[0]&b[2]&~b[0]) | (~a[2]&a[1]&~b[2]&b[1]&~b[0]); assign out[1] = (a[2]&a[1]&a[0]&b[3]) | (a[2]&~a[1]&~a[0]&b[3]) | (a[3]&~a[0]&b[3]&b[0]) | (a[3]&b[2]&b[1]&b[0]) | (a[3]&a[0]&b[3]&~b[0]) | (a[3]&b[2]&~b[1]&~b[0]) | (~a[3]&~a[2]&~a[1]&a[0]&b[1]) | (a[2]&a[1]&~a[0]&b[2]&b[1]) | (a[1]&~b[3]&~b[2]&~b[1]&b[0]) | (~a[2]&a[1]&~a[0]&b[3]&~b[0]) | (a[2]&a[1]&~a[0]&b[1]&~b[0]) | (a[2]&a[1]&b[2]&b[1]&~b[0]) | (a[1]&~a[0]&b[2]&b[1]&~b[0]) | (a[3]&~a[0]&~b[2]&b[1]&~b[0]) | (a[2]&~a[1]&~a[0]&~b[2]&b[1]&b[0]) | (~a[2]&a[1]&a[0]&b[2]&~b[1]&~b[0]) | (a[2]&~a[1]&~a[0]&b[2]&~b[1]&~b[0]) | (~a[2]&~a[1]&a[0]&b[1]&b[0]) | (a[1]&a[0]&~b[2]&~b[1]&b[0]) | (~a[2]&a[1]&~a[0]&~b[2]&b[1]&b[0]) | (~a[2]&a[1]&a[0]&~b[2]&b[1]&~b[0]); assign out[0] = (a[0]&b[0]); endmodule
Библиотека стандартных ячеек
NangateOpenCellLibrary.lib
Скрипт для запуска
lappend search_path "../libs" "../src" set target_library "NangateOpenCellLibrary.db" set link_library [list "*" $target_library] analyze -f <имя модуля>.v elaborate <имя модуля> uniquify current_design <имя модуля> check_design set_load [load_of [get_lib_pins NangateOpenCellLibrary/INV_X4/A]] [all_outputs] set_driving_cell -lib_cell DFFRS_X2 -library NangateOpenCellLibrary -pin Q [all_inputs] set_max_delay -to [all_outputs] 0 set_max_area 0 compile report_timing > result/timing_<имя модуля>.rpt report_area > result/area_<имя модуля>.rpt remove_design -all
Файлы для эксперимента
- Несжатые таблицы истинности для умножителей (.csv, 8MB)
- Сжатые Espresso таблицы истинности для умножителей (.csv, 4MB)
- Verilog на основе таблиц истинности для умножителей (.v, 4.3MB)