2013-10-03 6 views
0

Я пытаюсь передать код k-ближайшего соседа (в MATLAB) в Verilog, чтобы я мог использовать его в своем дизайне и в конечном итоге надеть плату FPGA. Теперь код и его операции довольно просты в MATLAB, потому что такие вещи, как создание нулевых и идентичных матриц или умножение 2D-матриц, удобно обрабатываются заранее созданными функциями. Я пытаюсь сделать то же самое в Verilog, но без использования циклов «for», поскольку их нужно использовать только в параллельных структурах и не очень эффективно (правильно?). Я могу обрабатывать одномерные массивы, но я не могу представить ничего для 2D-матриц, которые были бы эффективными (или, по крайней мере, такими же эффективными, как на аппаратных средствах). Любые советы будут полезны.Умножение 2D-массивов в Verilog

Спасибо заранее!

ответ

2

К сожалению, я думаю, что это будет намного больше, чем вы ожидали.

Помните, что verilog - это не язык программирования, а язык описания аппаратного обеспечения. Он не знает, что вы пытаетесь выполнить большие математические вычисления, одна операция умножения двух чисел - это самый высокий уровень абстракции, который вы можете получить.

Поэтому вы должны думать обо всех отдельных операциях add/multiply, которые входят в матричное умножение, и думать о том, как писать конечный автомат, который может выполнять каждую из этих операций, сохраняя при этом отслеживание всех промежуточных продуктов ,

Даже матрица с матрицей 4x4 требует более ста операций добавления/умножения, и вам придется описать процессор, который знает и может отслеживать все эти.

Вместо того, чтобы быть оператором одной строки, я бы предположил, что для кого-то нового с Verilog это может быть многонедельный проект для планирования, записи и проверки схемы умножения матрицы. Я знаю, что это не конкретный ответ, а просто хотел, чтобы вы знали о масштабах этого проекта.

Если вы хотите попробовать, начните с определения количества параллельных умножителей и сумматоров, которые вы можете позволить себе создать, а затем начните думать о том, как писать конечный автомат, который может отслеживать все отдельные операции добавления/умножения, а затем как обрабатывать все эти операции параллельно всем множителям и сумматорам, доступным вам за несколько тактов.

+0

Да, я знаю об ограничениях HDL. Infact, я только что внедрил пользовательскую реализацию AES на доске, поэтому я знаю, как много мучительно нужно планировать и сопоставлять каждую единицу. Однако, поскольку этот код относительно прост, я думал, что это будет меньше головной боли. Можете ли вы указать мне какой-то ссылочный код для больших множителей? – Sam29

+0

У меня есть пара потенциальных хитов путем поиска * opensores matrix multipication *, возможно, захочет проверить их. @ Sam29 – Tim

+0

спасибо за помощь. Прямо сейчас, так как я просто хочу «преобразовать» код в Verilog, эффективность для меня не слишком важна (на данный момент, конечно же, вся картинная вещь будет рассмотрена позже). Тем не менее, я просто хотел знать и избегать неправильных методов кодирования в Verilog для таких операций. – Sam29

0

для цикла является вашим другом, но только тогда, когда он используется в генерации, а не в последовательном коде (always/initial/function/task). Последовательные циклы могут привести к запутанному оборудованию, если вы не будете осторожны.

Вы можете в принципе закодировать это так же, как на любом другом языке, с (основной) проблемой, с которой вы не можете передавать массивы через порты модулей. Ниже приведен пример работы. Это было бы намного проще и яснее в VHDL (и, вероятно, SV, которого я не использую). Если вы собираетесь делать много такого, и вы только начинаете, вы должны сменить язык.

Аппаратное обеспечение квадратной матрицы 3x3, умноженное ниже, выполняется быстро, за счет большого количества аппаратного обеспечения. Он генерирует 9 единиц MAC, каждый из которых требует трех умножителей и двух сумматоров. вам нужно подумать о ширине бит; код в его нынешнем виде присваивает результат MAC 18-битовому значению, которое не будет работать вообще (код имитирует правильно, потому что значения в A и B являются небольшими).

Вам нужно подумать о ресурсах и сроках. Если у вас нет 27 множителей и 18 сумматоров, но вам не нужен ответ в спешке, а затем делитесь ими.В пределе вы можете построить очень компактное серийное оборудование за счет множества циклов и сложного управления.

module top; 

    wire[17:0]A[1:3][1:3]; // the matrices 
    wire[17:0]B[1:3][1:3]; 
    wire[17:0]C[1:3][1:3]; 

    wire[(9*18)-1:0] Abits; // bit-decomposed versions of the above 
    wire[(9*18)-1:0] Bbits; 
    wire[(9*18)-1:0] Cbits; 

    genvar i,j; 

    // set A and B with initial values 
    generate 
     for(i=0; i<3; i=i+1) 
     for(j=0; j<3; j=j+1) begin 
      assign A[i+1][j+1] = i*3 + j; 
      assign B[i+1][j+1] = i*3 + j + 1; 
     end 
    endgenerate 

    // decompose A and B, set C 
    generate 
     for(i=1; i<=3; i=i+1) 
     for(j=1; j<=3; j=j+1) begin 
      assign Abits[(((i-1)*3 + (j-1)) * 18)+17 -:18] = A[i][j]; 
      assign Bbits[(((i-1)*3 + (j-1)) * 18)+17 -:18] = B[i][j]; 
      assign C[i][j] = Cbits[(((i-1)*3 + (j-1)) * 18)+17 -:18]; 
     end 
    endgenerate 

    initial 
     #1 $display("%4d %4d %4d\n%4d %4d %4d\n%4d %4d %4d\n", 
        C[1][1], C[1][2],C[1][3], 
        C[2][1], C[2][2],C[2][3], 
        C[3][1], C[3][2],C[3][3]); 

    mmult3x3 U1(Abits, Bbits, Cbits); 
endmodule 

module mmult3x3 
    (input wire[(9*18)-1:0] AI, 
    input wire[(9*18)-1:0] BI, 
    output wire[(9*18)-1:0] CO); 

    wire[17:0]A[1:3][1:3]; 
    wire[17:0]B[1:3][1:3]; 
    wire[17:0]C[1:3][1:3]; 

    genvar i,j; 

    generate 
     for(i=1; i<=3; i=i+1) 
     for(j=1; j<=3; j=j+1) begin 
      assign A[i][j] = AI[(((i-1)*3 + (j-1)) * 18)+17 -:18]; 
      assign B[i][j] = BI[(((i-1)*3 + (j-1)) * 18)+17 -:18]; 
      assign CO[(((i-1)*3 + (j-1)) * 18)+17 -:18] = C[i][j]; 
     end 
    endgenerate 

    // this is the bit that matters - everything else just works around shortcomings 
    // in the language: 
    generate 
     for(i=1; i<=3; i=i+1) 
     for(j=1; j<=3; j=j+1) 
      assign C[i][j] = A[i][1]*B[1][j] + A[i][2]*B[2][j] + A[i][3]*B[3][j]; 
    endgenerate 
endmodule 
+0

Это интересный код. Я использовал почти то же самое для инициализации матриц. В любом случае, мне было интересно, будет ли лучше рассматривать каждую строку как отдельный массив и выполнять ops на нем, а затем получить вторую строку на следующих часах и т. Д. Таким образом, мне придется иметь дело только с массивом фиксированной ширины (скажем, 128 бит). Я знаю, что это довольно расплывчатый вопрос (вы не можете сказать, будет ли это работать, если вы не знаете, какие операции я говорю). Но для сложных операций это вариант? – Sam29

+0

Не уверен, что я тебя очень понимаю. Внутренний цикл работает по одной полной строке и по одному полному столбцу за раз, производя один единственный результат, и этот внутренний цикл реплицируется 9 раз, чтобы произвести все 9 результатов (для 3 на 3) «одновременно», т. Е. в том же такте. Это имеет смысл только в том случае, если у вас есть достаточное количество множителей и сумматоров для умножения всей матрицы за один цикл. Начните с определения количества множителей и сумматоров, сколько вам нужно, и сколько часов у вас есть. Теперь нарисуйте схему. После этого кодирование легко. – EML

+0

Ничего, я нашел ответ на свой вопрос. Но я говорил: поскольку Verilog не будет принимать 2D-массивы в качестве входных данных из входного порта, мне придется получать данные «по одной строке за раз», а затем хранить данные в двумерном массиве temp. Это займет M тактовых циклов для M строк, правильно? И как только я закончу получение ввода и сохраню его в 2D-матрице, я могу использовать ваше предложение, правильно? – Sam29

Смежные вопросы