Теперь пробуем решить простенькие задачки на Verilog. Начнем с того, где может понадобиться сравнение чисел: поиск максимального и минимального значения в массиве. Я предпочитаю сначала писать на C/C++, отлаживаться, а потом переносить код на Verilog. Так быстрее и надежнее, ведь в итоге должен получиться одинаковый результат в отладчике и в тестбенче.
Пусть и нас есть небольшой массив, в котором нужно найти минимальное число и максимальное. Решим задачу на Си:
Exported from Notepad++
Вывод: 0 4
На что тут можно обратить внимание? Результат находится за четыре прохода в цикле. Каждую итерация в цикле присутствует только одна переменная с текущим индексом, т.е. по сути можно пройтись с 0 индекса до 3, можно с 3 до 0, результат не измениться. Такой цикл можно разбить на два "как бы" параллельных с проходом 0..1 и 2..3. Или, если массив маленький, можно "как бы" за один проход сравнить все числа. Так максимальное значение за один такт можно найти:
Exported from Notepad++
Вывод: 4
Аналогично для минимального значения. Такой способ применим для относительно небольшой длины массива, потому что количество сравнений будет зависеть от длины и равно len-1.
Но ситуацию бывают разные. Предположим нам не нужно считать максимальное и минимальное значение за один такт, или стоит задача сэкономить ресурсы ПЛИС. Тогда тактика становится другой и в ход идет конвейер. Смысл такой: выполняем однотипные действия каждый такт, используя одни и те же ресурсы. Вместо 3 элементов сравнения в первом случае, будет использоваться одно сравнение.
Exported from Notepad++
Цена за конвейер: 4 такта считается максимальное значение и счетчик плюс триггера, хранящие промежуточные значения. Выигрыш в количестве логических элементов.
Пусть и нас есть небольшой массив, в котором нужно найти минимальное число и максимальное. Решим задачу на Си:
#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. Или, если массив маленький, можно "как бы" за один проход сравнить все числа. Так максимальное значение за один такт можно найти:
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 элементов сравнения в первом случае, будет использоваться одно сравнение.
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 такта считается максимальное значение и счетчик плюс триггера, хранящие промежуточные значения. Выигрыш в количестве логических элементов.
Комментариев нет:
Отправить комментарий