Возьмем в качестве примера модуль вычисления длины гипотенузы. Во-первых, я хочу его обобщить для случая отрицательных входных данных. Это может понадобиться для вычисления комплексных чисел. Во-вторых, такая модификация позволит кое-где сэкономить пару бит в расчетах. В-третьих, сделаем этот модуль параметризируемым.
Сложно написать не занудно про комплексные числа. Я и не буду, они просто есть, так же как и вещественные. Понадобятся они мне в дальнейшем, когда, надеюсь, перейду к FFT.
У комплексного числа есть реальная Re и мнимая Im составляющие, которые могут принимать любые значения. Они могут быть отрицательными. И это в какой-то степени даже хорошо, потому что квадрат отрицательного числа всегда будет положительным, а это значит что знаковый разряд при возведении в квадрат всегда == 0 и его можно отбросить, получая при этом не 32 разряда числа при 16 битном входном, а 31. Складывая два 31 битных числа мы получим 32 битное, а это значит, что не придется расширять представления числа вставкой нуля, как в wire [33:0] xx. Так же было много непонятных констант, которые хотелось бы определить и привязать к конкретным переменным. На самом деле в нашем модуле все зависит только от одной переменной: количества бит во входных словах x1,x2. Введем параметр DATA_IN_WIDTH и пусть он так же равен 16. x1_2 и x2_2 тогда получат длину DATA_WIDTH_SQUARING = 2*DATA_IN_WIDTH -1 = 31. Отнимаем мы единицу из-за уже упоминавшегося знакового разряда, равного нулю. Сумма квадратов x получит размер DATA_WIDTH_SUM = DATA_WIDTH_SQUARING+1 = 32. Квадратный корень из 32 битного числа займет 16 бит, при этом результат уже будет беззнаковым. Если раскрыть цикл for, то получится абсолютно те же выражения, что и в последнем примере отсюда. В итоге получается такой милый модуль, который сложно понять и в котором сложно разобраться. Но с другой стороны, это похоже на черный ящик, у которого есть параметр ширины входных данных и который выдает результат.
Exported from Notepad++
Сложно написать не занудно про комплексные числа. Я и не буду, они просто есть, так же как и вещественные. Понадобятся они мне в дальнейшем, когда, надеюсь, перейду к FFT.
У комплексного числа есть реальная Re и мнимая Im составляющие, которые могут принимать любые значения. Они могут быть отрицательными. И это в какой-то степени даже хорошо, потому что квадрат отрицательного числа всегда будет положительным, а это значит что знаковый разряд при возведении в квадрат всегда == 0 и его можно отбросить, получая при этом не 32 разряда числа при 16 битном входном, а 31. Складывая два 31 битных числа мы получим 32 битное, а это значит, что не придется расширять представления числа вставкой нуля, как в wire [33:0] xx. Так же было много непонятных констант, которые хотелось бы определить и привязать к конкретным переменным. На самом деле в нашем модуле все зависит только от одной переменной: количества бит во входных словах x1,x2. Введем параметр DATA_IN_WIDTH и пусть он так же равен 16. x1_2 и x2_2 тогда получат длину DATA_WIDTH_SQUARING = 2*DATA_IN_WIDTH -1 = 31. Отнимаем мы единицу из-за уже упоминавшегося знакового разряда, равного нулю. Сумма квадратов x получит размер DATA_WIDTH_SUM = DATA_WIDTH_SQUARING+1 = 32. Квадратный корень из 32 битного числа займет 16 бит, при этом результат уже будет беззнаковым. Если раскрыть цикл for, то получится абсолютно те же выражения, что и в последнем примере отсюда. В итоге получается такой милый модуль, который сложно понять и в котором сложно разобраться. Но с другой стороны, это похоже на черный ящик, у которого есть параметр ширины входных данных и который выдает результат.
/*
output: sqrt(x1^2 + x2^2)
*/
module test
#(parameter DATA_IN_WIDTH = 16)
(
input wire clk,
input wire signed [ DATA_IN_WIDTH-1: 0 ] x1,
input wire signed [ DATA_IN_WIDTH-1: 0 ] x2,
output wire [ DATA_IN_WIDTH-1: 0 ] y
);
localparam DATA_WIDTH_SQUARING = (2*DATA_IN_WIDTH) - 1;
wire [ DATA_WIDTH_SQUARING-1: 0 ] x1_2 = x1*x1;
wire [ DATA_WIDTH_SQUARING-1: 0 ] x2_2 = x2*x2;
localparam DATA_WIDTH_SUM = DATA_WIDTH_SQUARING+1;
wire [ DATA_WIDTH_SUM-1: 0 ] x = x1_2 + x2_2;
assign y[DATA_IN_WIDTH-1] = x[(DATA_WIDTH_SUM-1)-:2] == 2'b00 ? 1'b0 : 1'b1;
genvar k;
generate
for(k = DATA_IN_WIDTH-2; k >= 0; k = k - 1)
begin: gen
assign y[k] = x[(DATA_WIDTH_SUM-1)-:(2*(DATA_IN_WIDTH-k))] <
{y[DATA_IN_WIDTH-1:k+1],1'b1}*{y[DATA_IN_WIDTH-1:k+1],1'b1} ? 1'b0 : 1'b1;
end
endgenerate
endmodule
Комментариев нет:
Отправить комментарий