У меня есть w*y-битная ширина std_logic_vector
с именем matrix
, где w и y — целые числа. Я хочу, чтобы y-битная ширина std_logic_vector
называлась output
, чтобы ее биты одновременно присваивались И из w битов matrix
элементов.
Например, w=5 y=3:
output(2) <= matrix(14) and matrix(13) and matrix(12) and matrix(11) and matrix(10);
output(1) <= matrix(9) and matrix(8) and matrix(7) and matrix(6) and matrix(5);
output(0) <= matrix(4) and matrix(3) and matrix(2) and matrix(1) and matrix(0);
В примере вы можете видеть, что output
имеет длину y-бит, что равно 3, и каждый бит output
присваивается И w-битов matrix
, что равно 5.
Теперь я хочу написать это с помощью дженериков. Я пытался написать это в два цикла for..generate
, но я не могу с этим справиться. Что должно быть справа от output(i)
? Это также может быть реализовано по-другому, и я очень приветствую другие идеи. Это не должно быть так, как я думал.
library ieee;
use ieee.std_logic_1164.all;
entity module is
generic (
w : integer := 5; -- input width
y : integer := 3 -- output width
);
port (
matrix : in std_logic_vector(w * y - 1 downto 0); -- matrix
output : out std_logic_vector(y - 1 downto 0) -- output
);
end entity module;
architecture rtl of module is
begin -- architecture rtl
AND_FOR: for i in y - 1 downto 0 generate
AND_FOR2: for j in w - 1 downto 0 generate
output(i) <= ????;
end generate AND_FOR2;
end generate AND_FOR;
end architecture rtl;
Цель здесь — найти способ описать срезы с диапазоном элементов в ваших назначениях в качестве входных данных для сокращения И использовать тщательно разработанные границы в как можно меньшем количестве операторов генерации.
Операторы Generate привлекательны тем, что предоставляют статические индексированные имена или имена слайсов, сохраняя возможность синтеза. У нас нет способа разработать выражения различной сложности (здесь длины) в VHDL, что делает привлекательной сведение по И. В зависимости от инструментов синтеза вам может быть «рекомендовано» использовать ранее существовавшую функцию, такую как AND_REDUCE
из пакета Synopsys std_logic_misc.
В -2008 мы можем использовать унитарное И (зарезервированное слово, за которым следует операнд. В инструментах, совместимых с более ранними версиями стандарта VHDL, мы можем использовать вызов функции:
architecture rtl of module is
-- -2008 use unitary AND without parameter instead of call:
function reduce_and (inp: std_logic_vector) return std_logic is
variable retval: std_logic := '1';
begin
for i in inp'range loop
retval := retval and inp(i);
end loop;
return retval;
end function;
begin
AND_FOR:
for i in y - 1 downto 0 generate
output(i) <= reduce_and(matrix((i + 1) * w - 1 downto i * w));
end generate;
describe_outputs:
process
begin
report "matrix'range is (" & integer'image(matrix'left) &
" downto " & integer'image(matrix'right) & ")";
for i in y - 1 downto 0 loop
report "output(" & integer'image(i) & ") <= reduce_and(matrix(" &
integer'image((i + 1) * w - 1 ) & " downto " &
integer'image (i * w) & ")";
end loop;
wait;
end process;
end architecture;
Оператор for generate создаст блок для каждого значения его параметра for generate (здесь i). Он объявлен как константа в области описания блока. И w, и y являются глобально статическими универсальными константами, и в результате диапазон матрицы также является глобально статическим. В основном это означает, что использование оператора генерации, подобного этому, приводит к операторам присваивания, пригодным для синтеза.
Оператор процесса, помеченный describe_outputs
, добавлен, чтобы продемонстрировать эквивалентность (способность алгоритмически описывать элементы, объединяемые по И) с вашими предыдущими операторами присваивания, потому что вы не продемонстрировали значение для матрицы и ожидаемый результат вместе с испытательным стендом. Процесс можно устранить.
Пока вы используете значения для w
и x
, которые не приводят к нулевому диапазону или нулевому срезу, этот метод должен работать с жестко закодированным направлением (downto
).
Операторы отчета зависят от реализации (с необходимой информацией «заголовок»). Здесь показано для ghdl:
%: ghdl -a module.vhdl
%: ghdl -e module
%: ghdl -r module
module.vhdl:35:9:@0ms:(report note): matrix'range is (14 downto 0)
module.vhdl:38:13:@0ms:(report note): output(2) <= reduce_and(matrix(14 downto 10)
module.vhdl:38:13:@0ms:(report note): output(1) <= reduce_and(matrix(9 downto 5)
module.vhdl:38:13:@0ms:(report note): output(0) <= reduce_and(matrix(4 downto 0)
%:
Мне действительно нужно было reduce_xor
, поэтому я изменил variable retval: std_logic := '1';
на variable retval: std_logic := '0';
, а также, очевидно, and
на xor
, и использовал это решение. Это работает очень хорошо! Спасибо.
Вы действительно можете смоделировать это с помощью двумерного генератора, но вам нужен промежуточный сигнал, соответствующий выходам двухвходовых логических элементов И.
Давайте рассмотрим ваш ввод как матрицу y
строк, умноженных на w
столбцов. Для простоты объяснения мы будем обозначать m(i,j)
элемент в строке i
, столбце j
матрицы m
. Так что ваш matrix(i*w+j)
обозначается matrix(i,j)
.
Вы хотите, чтобы output(i)
, где 0 <= i <= y-1
, было побитовым и строкой i
из matrix
. Вы можете использовать матрицу y
строк, умноженных на w-1
столбцы tmp
, чтобы получить результаты 2-входных И. tmp(i,0)
будет AND matrix(i,0)
и matrix(i,1)
. Тогда tmp(i,1)
будет И между tmp(i,0)
и matrix(i,2)
... Наконец, tmp(i,w-2)
будет И между tmp(i,w-3)
и matrix(i,w-1)
, и это также будет output(i)
, которое вы хотите.
Кодирование VHDL:
library ieee;
use ieee.std_logic_1164.all;
entity module is
generic(
w: integer := 5;
y: integer := 3
);
port(
matrix: in std_logic_vector(w * y - 1 downto 0);
output: out std_logic_vector(y - 1 downto 0)
);
end entity module;
architecture rtl of module is
type matrix_t is array(natural range <>, natural range <>) of std_logic;
signal tmp: matrix_t(0 to y - 1, 0 to w - 2);
begin
and_for: for i in 0 to y - 1 generate
tmp(i, 0) <= matrix(i * w) and matrix(i * w + 1);
and_for2: for j in 1 to w - 2 generate
tmp(i, j) <= tmp(i, j - 1) and matrix(i * w + j + 1);
end generate and_for2;
output(i) <= tmp(i, w - 2);
end generate and_for;
end architecture rtl;
Демо:
library ieee;
use ieee.std_logic_1164.all;
entity module_sim is
end entity module_sim;
architecture sim of module_sim is
constant w: natural := 5;
constant y: natural := 3;
signal matrix: std_logic_vector(w * y - 1 downto 0);
signal output: std_logic_vector(y - 1 downto 0);
begin
u0: entity work.module(rtl)
port map(
matrix => matrix,
output => output
);
process
begin
matrix <= (others => '1');
wait for 1 ns;
report to_string(output);
for i in 0 to y - 1 loop
matrix(i * w) <= '0';
end loop;
wait for 1 ns;
report to_string(output);
matrix <= (others => '1');
wait for 1 ns;
report to_string(output);
wait;
end process;
end architecture sim;
$ ghdl -a --std=08 module_sim.vhd
$ ghdl -r --std=08 module_sim
module_sim.vhd:50:5:@1ns:(report note): 111
module_sim.vhd:55:5:@2ns:(report note): 000
module_sim.vhd:58:5:@3ns:(report note): 111
Но, как предлагается в другом ответе, использование функции сокращения И вместо самого внутреннего оператора генерации проще и менее подвержено ошибкам.
В прошлые дни мы беспокоились о том, сколько процессов (здесь w * y) и сколько раз они будут вызваны до того, как продвинется время моделирования. Теперь не так много, ограничивающим фактором производительности моделирования является объем памяти в модели, особенно для сигналов. Существует также единая модель процесса (выражение вызова функции, требующее регистрации вывода только для достаточно больших значений w, чтобы иметь значение глубины затвора, а также зависит от архитектуры логической ячейки FPGA для синтеза). Инструмент синтеза с надлежащими ограничениями может дать один и тот же ответ из любого из этих описаний.
Спасибо, Рено, я ценю. Это похоже на правильное решение, однако, как вы также упомянули, другой ответ работал довольно хорошо и проще, я думаю, что пока буду придерживаться его.
Если у вас есть доступ к VHDL 2008, я полагаю, что у него есть сокращение и оператор; если нет, то не так уж сложно закодировать его в функции самостоятельно. При этом вам понадобится только один уровень для генерации. В качестве альтернативы вы можете заменить второй for generate на процесс и цикл for и сохранить продукт во временной переменной. После цикла for сохраните переменную в желаемом выходном бите. См. stackoverflow.com/questions/20296276/….