Проблема отображения VHDL на макетной плате

У меня очень неприятная проблема, и я был бы очень признателен за помощь.

Я пытаюсь протестировать блок оперативной памяти с помощью переключателей и светодиодов на плате разработки Nexys A7-100T FPGA. Мой код синтезируется нормально, но не работает из-за ошибок, показанных на изображении ниже.

Я также показал свой файл ограничений и файл кода верхнего уровня.

Я новичок в платах FPGA и не уверен, что делаю неправильно. Я проверил этот код на тестовом стенде, и он отлично работает. Хотел бы отобразить его на FPGA, чтобы узнать, как это сделать.

РЕДАКТИРОВАТЬ

Я закомментировал часы в файле ограничений, так как они вызвали еще больше ошибок.

Спасибо!

введите описание изображения здесь

Файл ограничений



#create_clock -period 10.000 -name clk -waveform {0.000 5.000} [get_ports clk]
#set_property -dict { PACKAGE_PIN E3    IOSTANDARD LVCMOS33 } [get_ports { clk }];

set_property -dict { PACKAGE_PIN P17   IOSTANDARD LVCMOS33 } [get_ports { Set_Button }]; #IO_L12P_T1_MRCC_14 Sch=btnl
set_property -dict { PACKAGE_PIN M17   IOSTANDARD LVCMOS33 } [get_ports { Enable_Button }]; #IO_L10N_T1_D15_14 Sch=btnr

set_property -dict { PACKAGE_PIN J15   IOSTANDARD LVCMOS33 } [get_ports { RAM_Address[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0]
set_property -dict { PACKAGE_PIN L16   IOSTANDARD LVCMOS33 } [get_ports { RAM_Address[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1]
set_property -dict { PACKAGE_PIN M13   IOSTANDARD LVCMOS33 } [get_ports { RAM_Address[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2]
set_property -dict { PACKAGE_PIN R15   IOSTANDARD LVCMOS33 } [get_ports { RAM_Address[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3]

set_property -dict { PACKAGE_PIN H17   IOSTANDARD LVCMOS33 } [get_ports { Data_out[0] }]; #IO_L18P_T2_A24_15 Sch=led[0]
set_property -dict { PACKAGE_PIN K15   IOSTANDARD LVCMOS33 } [get_ports { Data_out[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1]
set_property -dict { PACKAGE_PIN J13   IOSTANDARD LVCMOS33 } [get_ports { Data_out[2] }]; #IO_L17N_T2_A25_15 Sch=led[2]
set_property -dict { PACKAGE_PIN N14   IOSTANDARD LVCMOS33 } [get_ports { Data_out[3] }]; #IO_L8P_T1_D11_14 Sch=led[3]

Файл верхнего уровня



library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.Architecture_size.ALL;

entity RAM_Block is
 Port ( RAM_Address : in std_logic_vector (Data_width-1 downto 0); 
        Data_in  : in std_logic_vector (Data_width-1 downto 0);
        Set_Button : in std_logic;
        Enable_Button : in std_logic;
        Data_out : out std_logic_vector (Data_width-1 downto 0));
end RAM_Block;

architecture Behavioral of RAM_Block is

component Enabler_Block is
 Port ( A : in std_logic_vector(Data_width-1 downto 0);
        Enable : in std_logic;
        Q : out std_logic_vector(Data_width-1 downto 0));
end component;

type memory is array (0 to 3) of std_logic_vector (Data_width-1 downto 0);
signal RAM : memory := ("0000" , "0000" , "0000" , "0000");
signal RAM_output : std_logic_vector (Data_width-1 downto 0);
signal RAM_Address_int : integer;


begin



Enabler_Block_instance : Enabler_Block port map (A => RAM_output , Enable => Enable_Button , Q => Data_out);

RAM_Address_int <= conv_integer(unsigned(RAM_Address)); 

   Process (Set_Button , Enable_Button)

    begin

     if(rising_edge(Set_Button) and Set_Button = '1') then
        RAM(RAM_Address_int) <= Data_in;

     end if;

     if(rising_edge(Enable_Button) and Enable_Button = '1') then
        RAM_output <= RAM(RAM_Address_int);

     end if;

    end Process;

end Behavioral;

Здесь есть две вещи: во-первых, вы должны быть осторожны со стилем кодирования. особенно с часами. Вам нужно кодировать определенным образом, чтобы инструмент идентифицировал его как FF или RAM. На Vivado есть языковые шаблоны о том, как кодировать RAM. Во-вторых, все часы должны быть подключены к PIN-коду с поддержкой часов для эффективной маршрутизации.
Это определенно то, что часы, которые вы использовали в дизайне, не подключены к тактовому выводу FPGA. Enable_Button считается часами и подключен M17, который не является контактом CC.
Вы смогли это исправить?
@MituRaj Да, я дал ответ, чтобы объяснить, как проблема была решена, спасибо за вашу помощь!

Ответы (4)

Проблема в утверждениях:

if(rising_edge(Set_Button) and Set_Button = '1')
.
.
if(rising_edge(Enable_Button) and Enable_Button = '1')

Когда вы синтезируете этот код, синтезатор распознает эти два сигнала как часы в вашем проекте. Это также входные порты в вашем модуле. Если эти сигналы действительно были тактовыми входами в вашем проекте (что я не думаю, что вы намеревались это сделать), вы должны сопоставить их с тактовыми выводами в FPGA. В противном случае синтезатор не сможет использовать выделенную тактовую маршрутизацию от соответствующих IO через BUFG к синхронизируемым ими триггерам. Отсюда и сообщения об ошибках.

Ну, в любом случае, я не думаю, что вы собирались использовать их как часы, так что это то, что вы могли бы искать вместо этого -

if rising_edge(clk) then

   if Enable_button = '1' then 
      ..
   end if

   if Set_button = '1' then
      ...
   end if   

end if

Ваш дизайн как таковой вообще не синхронизирован.

Это будет сложно синтезировать, так как регистры в логических блоках имеют тактовый сигнал и вход разрешения, и предполагается, что FF переключается по переднему фронту тактового сигнала, пока установлено разрешение.

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

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

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

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

Проблема должна исчезнуть, если вы действительно сделаете этот дизайн синхронизированным.

Спасибо за Ваш ответ. Хорошо, теперь я вижу, что Vivado не нравится, однако весь мой дизайн основан на этом. У меня никогда не было этой проблемы во время моделирования, но теперь, когда я использую плату FPGA, я вижу, что мои проекты не будут работать. Не могли бы вы порекомендовать мне изменить мой дизайн, чтобы все компоненты синхронизировались, а затем в моих процессах решить, следует ли устанавливать или включать, основываясь на входных данных по переднему фронту синхронизации? По крайней мере, это потом будет синтезироваться на плате?
@David777 Стиль плохой и просто не будет работать для большинства VHDL, но для чего-то столь же простого, как то, что у вас есть здесь, определение края LUT будет работать, хотя я скептически отношусь к тому, что вы фактически запишете ОЗУ. Если все, что вам нужно прямо сейчас, это заставить некоторые светодиоды мигать, просто отключите выделенную маршрутизацию часов, как указано в сообщении об ошибке, и в следующий раз примите во внимание уроки Саймона и Миту Раджа.
@DonFusili Я понимаю, что ты имеешь в виду, это плохой пример. Однако это будет для реального блока ОЗУ, я просто использовал плату FPGA с кнопками в качестве набора и включения входов, чтобы ускорить тестирование различных комбинаций данных.

В сообщении говорится, что один из выводов используется в качестве часов, но на самом деле этот вывод не подходит для использования в качестве часов. Я бы сначала избавился от лишних "и Set_Button = '1')" и "и Enable_Button = '1')". Вам нужна только часть «rising_edge».

Вы также должны разделить процесс на два процесса и сделать каждый из них чувствительным к своим часам.

Если вы все еще получаете сообщение об ошибке, можете ли вы выбрать разные контакты для «Set_Button» и «Enable_Button»?

Спасибо за ваш совет. Я разделил процессы и изменил их список чувствительности, и это все равно не понравилось. Пробовал также несколько разных пинов, но безрезультатно. См. ответ Саймона Рихтера в моем комментарии выше.
@ Дэвид777 . Попробуйте удалить ограничение вывода Xilinx для Set_Button и Enable_Button. Посмотрите, будет ли это работать с Xilinx, выбирающим булавку.

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

Однако это вызвало у меня больше проблем во всем моем дизайне, поскольку у меня есть такая же проблема в другом коде VHDL. Спасибо всем за помощь. Я принял ответ, однако ответ каждого был очень полезен и очень ценен!



library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.Architecture_size.ALL;

entity RAM_Block is
 Port ( Clock : in std_logic;
        RAM_Address : in std_logic_vector (Data_width-1 downto 0); 
        Data_in  : in std_logic_vector (Data_width-1 downto 0);
        Set : in std_logic;
        Enable : in std_logic;
        Data_out : out std_logic_vector (Data_width-1 downto 0);
        RAM_Address_LED : out std_logic_vector (Data_width-1 downto 0);
        Data_in_LED : out std_logic_vector (Data_width-1 downto 0));
end RAM_Block;

architecture Behavioral of RAM_Block is

component Enabler_Block is
 Port ( A : in std_logic_vector(Data_width-1 downto 0);
        Enable : in std_logic;
        Q : out std_logic_vector(Data_width-1 downto 0));
end component;

type ram_type is array (0 to 3) of std_logic_vector (Data_width-1 downto 0);
signal RAM : ram_type := (others => "0000");
signal RAM_output : std_logic_vector (Data_width-1 downto 0);
signal RAM_Address_int : integer;


begin

Data_in_LED <= Data_in; 

RAM_Address_LED <= RAM_Address;

Enabler_Block_instance : Enabler_Block port map (A => RAM_output , Enable => Enable , Q => Data_out);

RAM_Address_int <= conv_integer(unsigned(RAM_Address)); 

   Process (Clock)

    begin

     if(rising_edge(Clock)) then
     
       if(Set = '1') then
        RAM(RAM_Address_int) <= Data_in;
        
       end if;
       
     end if;
     
    end process;
    
    Process (Clock)

     begin

     if(rising_edge(Clock)) then
     
        if(Enable = '1') then
         RAM_output <= RAM(RAM_Address_int);
         
        end if;  
     end if;

    end Process;
   
end Behavioral;

```