Редактировать: как кто-то указал, я сначала только указал, как установить входные сигналы, и привел в качестве примера два особых случая.Позвольте мне попытаться объяснить, как это работает.Хорошим началом для этого является ваш вопрос:
почему ~ (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