Понимание простого кругового алгоритма verilog-кода арбитра - PullRequest
3 голосов
/ 06 марта 2019

Взгляните на следующий арбитр.v код:

Кто-то сказал мне подумать о том, что rr_arbiter - это упрощенная схема пульсации заимствования , которая обертываетвокруг.

'base' - это один горячий сигнал, указывающий первый запрос, который следует рассмотреть на получение гранта.

да?Ребята, вы понимаете, как генерировать «базовый» входной сигнал?

Обратите внимание на вычитание.Логика заимствования заставляет его искать следующий установленный бит.

почему ~ (double_req-base)?

module arbiter (
    req, grant, base
);

parameter WIDTH = 16;

input [WIDTH-1:0] req;
output [WIDTH-1:0] grant;
input [WIDTH-1:0] base;

wire [2*WIDTH-1:0] double_req = {req,req};
wire [2*WIDTH-1:0] double_grant = double_req & ~(double_req-base);
assign grant = double_grant[WIDTH-1:0] | double_grant[2*WIDTH-1:WIDTH];

endmodule

Ответы [ 2 ]

2 голосов
/ 06 марта 2019

Редактировать: как кто-то указал, я сначала только указал, как установить входные сигналы, и привел в качестве примера два особых случая.Позвольте мне попытаться объяснить, как это работает.Хорошим началом для этого является ваш вопрос:

почему ~ (double_req-base)?

Как кто-то указал вам, это основано на принципе Волновой заем вычитает .Когда вы вычитаете одно число из другого, независимо от используемой вами системы счисления, вы начинаете с самого низкого порядка и пытаетесь вычесть два числа из одного порядка.В двоичном примере это будет выглядеть так:

1011     =    11
0010 -   =     2 -
──────        ────
1001     =     9

Как видите, 1 - 1 является действительным и дает 0.Однако, если это невозможно, вы можете одолжить с более высокого номера заказа. Это изображение показывает простой пример того, как это выглядит в десятичной системе.Примером в десятичной системе может быть:

1001     =     01(10)1     =    9
0010 -   =     00  1 0 -   =    2 - 
──────         ─────────        ───
0111     =     01  1 1     =    7

Поскольку 0 - 1 невозможно во второй позиции, мы берем 1 из четвертой позиции, устанавливаем третью позицию в 1и установите вторую позицию на 10 (так, 2 в десятичной системе).Это очень похоже на пример в десятичной системе, который я выложил до .

Важно для арбитра: следующая 1 из исходного числа (req), видимая с позицииbase, будет установлен на ноль.Все числа между базовой позицией и этим 0 будут установлены на 1.После инвертирования результата вычитания, только эта позиция будет 1, как видно из базы.

Однако числа с более низким порядком, чем основание, могут все еще быть 1 с этой техникой.Поэтому мы соединяем исходное число с вашим рассчитанным числом (double_req & ~(double_req-base)).Это гарантирует, что возможные 1 с в позициях ниже , чем base исключены.

Наконец, тот факт, что он удвоился, гарантирует, что у него не будет исчерпаны позиции для заимствования.Если ему необходимо позаимствовать из этого «второго» удвоенного блока, дизъюнкция (double_grant[WIDTH-1:0] | double_grant[2*WIDTH-1:WIDTH]) гарантирует, что она возвращает правильный индекс.Я добавил пример для этого в приведенные ниже примеры.

Исходное сообщение

Вы можете интерпретировать base как начальный индекс в req.Это первый бит, который код будет рассматривать для арбитража.Вы должны установить это значение на last_arbitrated_position + 1.

Взгляните на 4-битный (псевдокод) пример, который я создал ниже.Давайте возьмем несколько произвольных чисел:

req  = 4'b1101 // Your vector from which one position should be arbitrated
base = 4'b0010 // The second position is the first position to consider

Теперь из arbiter.v следует следующее:

double_req   = 1101 1101
double_grant = 1101 1101 & ~(1101 1011) = 1101 1101 & 0010 0100 = 0000 0100

На последних шагах arbiter.v затем фактически назначает позицию, которая должнапредоставлено:

grant = 0100 | 0000 = 0100

Это правильно, потому что мы установили вторую позицию в качестве базы, а следующая действительная позиция была третьей.Другой пример, где основание является позицией, которая также действительна в req, это:

req  = 4'b1111
base = 4'b0010
double_req   = 1111 1111
double_grant = 1111 1111 & ~(1111 1101) = 1111 1111 & 0000 0010 = 0000 0010
grant = 0010 | 0000

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

Пример кода, который вы разместили, также заботится о переносе наиболее значимого бита.Это означает, что если вы установите основание, но не существует действительной позиции, превышающей это основание, оно обернется и начнет арбитраж с младшего бита.Пример для этого случая будет:

req  = 4'b0010
base = 4'b0100
double_req   = 0010 0010
double_grant = 0010 0010 & ~(1110 0001) = 0010 0010 & 0001 1110 = 0010 0000
grant = 0000 | 0010
1 голос
/ 07 марта 2019

Цель арбитра - выяснить, какой запрос удовлетворить, и избежать повторного предоставления одному и тому же источнику.

Теперь предположим, что у нас установлено несколько req битов, а base, то есть состояние ранее предоставленного запроса, смещено влево на 1.

Итак, ваша задача - найти первый установленный бит слева от базового бита (или у него) для предоставления запроса. Операция вычитания перевернет все биты, оставшиеся от базовый бит, заканчивающийся первым установленным битом, например

 1100 << req
-0010 << base
 ====
 1010
 -^^-
  ^

бит req[2] - это тот, который мы хотим удовлетворить запрос. Это было переключено на «0». Все биты слева от него и биты справа от базового бита не были изменены. Нам нужно получить бит, который был изменен последним, на «0».

Способ сделать это - 'и' значение запроса с инверсией результата вычитания. Измененные биты всегда будут иметь один шаблон: крайний левый будет «0», а остальные будут «1». Этот крайний левый край будет находиться точно в том месте, где в запросе была цифра «1». Таким образом, инверсия сделает его равным 1 и инвертирует все неизмененные биты влево и вправо. Добавление его к исходному запросу эффективно избавит от неизмененных битов и гарантирует сохранение вновь найденного «1».

 1010 << result of subtraction
~0101 << ~(req-base)
&1100 << req
=0100

Теперь проблема возникает, если мы движемся к переполнению:

 0010
-1000
 ====
 1010
~0101
&1010
=0000 << oops

Но мы хотим получить бит [1] из запроса. Чтобы решить эту проблему, нужно объединить еще одну копию req перед этой и продолжить вычитание, чтобы получить младший бит в верхней части. Часть:

 0010 0010
-0000 1000
 ====
 0001 1010
~1110 0101
&0010 0010
=0010 0000

теперь нам нужно выбирать только верхнюю и нижнюю части:

0010 | 0000 = 0010

вот вы, ваш результат.

...