вторник, 15 октября 2013 г.

Параметризация модулей

Возьмем в качестве примера модуль вычисления длины гипотенузы. Во-первых, я хочу его обобщить для случая отрицательных входных данных. Это может понадобиться для вычисления комплексных чисел. Во-вторых, такая модификация позволит кое-где сэкономить пару бит в расчетах. В-третьих, сделаем этот модуль параметризируемым.
Сложно написать не занудно про комплексные числа. Я и не буду, они просто есть, так же как и вещественные. Понадобятся они мне в дальнейшем, когда, надеюсь, перейду к 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++
/* 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

Комментариев нет:

Отправить комментарий