четверг, 26 сентября 2013 г.

Поиск MAX&MIN в массиве

Теперь пробуем решить простенькие задачки на Verilog. Начнем с того, где может понадобиться сравнение чисел: поиск максимального и минимального значения в массиве. Я предпочитаю сначала писать на C/C++, отлаживаться, а потом переносить код на Verilog. Так быстрее и надежнее, ведь в итоге должен получиться одинаковый результат в отладчике и в тестбенче.

Пусть и нас есть небольшой массив, в котором нужно найти минимальное число и максимальное. Решим задачу на Си:
Exported from Notepad++
#include <iostream> using namespace std; const short len = 4; short val[len] = {1,0,2,4}; short min_val(short *x, short len) { short min = *x; for(int i = 0; i < len; i++) { if(min > *(x+i)) min = *(x+i); } return min; } short max_val(short *x, short len) { short max = *x; for(int i = 0; i < len; i++) { cout << max << "\t" << *(x+i) << endl; if(max < *(x+i)) max = *(x+i); } return max; } int main () { short min = min_val(val, len); short max = max_val(val,len) cout << min << " " << max; return 0; }































Вывод: 0 4

На что тут можно обратить внимание? Результат находится за четыре прохода в цикле. Каждую итерация в цикле присутствует только одна переменная с текущим индексом, т.е. по сути можно пройтись с 0 индекса до 3, можно с 3 до 0, результат не измениться. Такой цикл можно разбить на два "как бы" параллельных с проходом 0..1 и 2..3. Или, если массив маленький, можно "как бы" за один проход сравнить все числа. Так максимальное значение за один такт можно найти:
Exported from Notepad++
localparam len = 4; reg signed [ 3 : 0 ] val[ 0 : len-1 ]; initial begin val[0] = 1; val[1] = 0; val[2] = 2; val[3] = 4; end wire signed [ 3 : 0 ] tmp1 = val[0] > val[1] ? val[0] : val[1]; wire signed [ 3 : 0 ] tmp2 = val[2] > val[3] ? val[2] : val[3]; wire signed [ 3 : 0 ] bigger = tmp1 > tmp2 ? tmp1 : tmp2;











Вывод: 4

Аналогично для минимального значения. Такой способ применим для относительно небольшой длины массива, потому что количество сравнений будет зависеть от длины и равно len-1.

Но ситуацию бывают разные. Предположим нам не нужно считать максимальное и минимальное значение за один такт, или стоит задача сэкономить ресурсы ПЛИС. Тогда тактика становится другой и в ход идет конвейер. Смысл такой: выполняем однотипные действия каждый такт, используя одни и те же ресурсы. Вместо 3 элементов сравнения в первом случае,  будет использоваться одно сравнение.
Exported from Notepad++
module test( input wire clk, output wire [ 3 : 0 ] big ); localparam len = 4; reg signed [ 3 : 0 ] val[ 0 : len-1 ]; initial begin val[0] = 1; val[1] = 0; val[2] = 2; val[3] = 4; end reg [ 1 : 0 ] cnt = 2'b0; reg signed [ 3 : 0 ] r_big = 4'b0; reg signed [ 3 : 0 ] r_out = 4'b0; always@(posedge clk) begin cnt <= cnt + 1'b1; case(cnt) 2'b00: begin r_big <= val[cnt]; r_out <= r_big; end default: if(r_big < val[cnt]) r_big <= val[cnt]; endcase end assign big = r_out; endmodule






























Цена за конвейер: 4 такта считается максимальное значение и счетчик плюс триггера, хранящие промежуточные значения. Выигрыш в количестве логических элементов.

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

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