Понимание простого кода verilog арбитра циклического перебора

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

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

«база» — это один горячий сигнал, указывающий на первый запрос, который следует рассмотреть для предоставления.

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

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

почему ~(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

person kevin    schedule 06.03.2019    source источник


Ответы (2)


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

почему ~(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
person Silicon1602    schedule 06.03.2019
comment
Вы показали, что это работает в двух конкретных случаях, но можете ли вы объяснить, почему это работает в целом? - person EML; 06.03.2019
comment
@EML, вы правы, сначала я ответил только на ту часть вопроса, в которой говорилось, как использовать base. Было бы лучше включить общее объяснение. Поэтому я отредактировал свой ответ и добавил более общее объяснение вычитателя заимствования пульсаций и того, как этот арбитр его использует. - person Silicon1602; 06.03.2019

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

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

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

 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

вот, вы получили свой результат.

person Serge    schedule 06.03.2019
comment
@ Silicon1602 Не забудьте зафиксировать и удерживать основание, пока не будет выбран следующий победитель. ‹-- Как я собираюсь этого добиться? Использование механизма приоритетной обратной связи с использованием элемента И для достижения этой цели приведет к включению элемента ИЛИ. и проблемы разветвления в случае, когда у нас есть 10 строк req для обработки в циклическом режиме. - person kevin; 08.03.2019