SPÄTER BEARBEITEN:
1. Ich habe das Kintex7-Gerät nach der Implementierung auch visuell untersucht (dh Verbindungen usw.) und alles sieht in Ordnung aus - keine Verbindungen, die darauf hinweisen würden, dass die Dinge nicht in Ordnung wären (natürlich bin ich nicht den ganzen Weg zurück zu gegangen). Eingänge, da ich annehme, dass, wenn das 2-FIFO-basierte Loopback funktioniert, der Addierer irgendwie kaputt ist).
Außerdem bin ich auf diesen Xilinx Answer Record gestoßen . Ich habe versucht, den vorgeschlagenen Fix anzuwenden, aber es schien nicht zu funktionieren.
2. Beim zweiten Ansatz (manuelle Eingabe auf Spartan6) stellte ich fest, dass das Problem ein fehlerhafter Schalter war, der den Eingabewert nicht richtig einstellen würde, wenn nicht darauf geachtet wurde. Ich habe nochmals sorgfältig getestet und diesmal den richtigen Wert erhalten. Ich habe dieses Design jedoch geändert, um stattdessen nur die Eingaben von ROM/LUT zu nehmen und ein Byte nach dem anderen anzuzeigen, abhängig von den als Eingaben angegebenen Auswahlschaltern. Es ist keine Uhr mehr beteiligt. Das Problem mit dem ursprünglichen Vivado-basierten Projekt besteht weiterhin, was mich zu der Annahme veranlasst, dass es sich um ein Synthese-/Implementierungs-/fehlerhaftes Hardwareproblem handeln könnte.
ORIGINALE NACHRICHT:
Ich habe ein xillybus-basiertes PCIe-Design, das komplexer werden soll, aber im Moment liest es inkrementell nur Paare von 32-Bit-Werten aus einem 32-Bit-Eingangs-FIFO, das mit xillybus verbunden ist, addiert sie und schreibt sie in ein 32-Bit-Ausgangs-FIFO, das mit xillybus verbunden ist.
Jetzt sehe ich folgendes Problem:
ANMERKUNG 1: Die Ausgangswellenform der Verhaltenssimulation (RTL-Pegel, Vorsynthese) gibt korrekte Werte zurück, es ist die tatsächliche Implementierung auf der Platine, bei der ein oder mehrere Bits umgedreht zu sein scheinen ( gegenüber dem erwarteten Wert, der derselbe ist wie der Ausgang der Simulation)
ANMERKUNG 2: Ich verwende zum Beispiel die Werte 0x3F800000
und 0x3F800000
(ja, zweimal den gleichen Wert), was nach und nach addiert werden sollte 0x7F000000
- wird unten erwähnt was das (falsche) Ergebnis in jedem Szenario war:
0x7E000100
(denken Sie daran, der Loopback-Test funktioniert).0x6F00000
(näher, da nur ein bisschen falsch, aber immer noch nicht genug)Beachten Sie, dass ich keine Beschwerden über Verstöße gegen Zeitbeschränkungen erhalte - und ich habe sowieso viele Möglichkeiten ausprobiert, um dem Problem auf den Grund zu gehen (dh einige Möglichkeiten herauszufiltern), aber ich bin zu keinem Ergebnis gekommen. Fürs Protokoll, ich habe sogar den einfachen Addierer in eine 2-Level-Pipeline umgewandelt, um "sicherzustellen", dass genug Zeit für die Berechnung des Ergebnisses bleibt, aber das Ergebnis war dasselbe (falsch).
Ich kann anscheinend keine Post-Synthese- oder Post-Implementierungs-Funktions- oder Timing-Simulation ausführen, da ich eine lästige Fehlermeldung bekomme
FEHLER: [VRFC 10-716] formaler Port o des Modus out kann nicht mit dem tatsächlichen Port pcie_perst_b_ls des Modus in verknüpft werden, [...]
Beachten Sie, dass ich Vivado 2014.2 verwende (was ein bisschen alt ist, aber wäre das wirklich das Problem?)
Unten der Code für die 2 Ansätze (Xillybus-basierte PCIe-gesteuerte E/A und einfache physische E/A). Leider konnte ich es nicht besser formatieren:
Ansatz für die Kintex-7 PCIe-basierte I/O:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity fsm is
port (
data_in : in std_logic_vector(31 downto 0);
data_out : out std_logic_vector(31 downto 0);
rd_en : out std_logic;
in_fifo_empty : in std_logic;
wr_en : out std_logic;
out_fifo_full : in std_logic;
clk, rst : in std_logic
);
end fsm;
architecture Behavioral of fsm is
component core
port (
operand_A_ieee, operand_B_ieee : in std_logic_vector(31 downto 0);
result_ieee : out std_logic_vector(31 downto 0);
clk, rst : in std_logic
);
end component;
-- pipeline_depth and pipeline_wr_status are used (only) for pipelined cores to assert wr_en when needed
-- ('1' added to the MSB of pipeline_wr_status when the second 32-bit operand is read and therefore the
-- core processing starts with valid data, so that it signals when a valid result reached the end of the core)
--constant pipeline_depth : integer := 10;
--signal pipeline_wr_status : std_logic_vector(pipeline_depth - 1 downto 0) := (others => '0');
type state_type is ( start, readA, waitB, addAB );
signal state, next_state: state_type;
signal operand_A_ieee : std_logic_vector(31 downto 0) := (others => '0');
signal result_ieee : std_logic_vector(31 downto 0);
begin
core_inst: core
port map (
operand_A_ieee => operand_A_ieee,
operand_B_ieee => data_in,
result_ieee => data_out,
clk => clk,
rst => rst
);
-- The loopback test (remove core_inst above) works as expected - in the out FIFO the value read from the in FIFO is saved
--data_out <= data_in;
SL: process (clk, rst, state, next_state, data_in)--, pipeline_wr_status)
begin
if rising_edge(clk) then
state <= next_state;
if state = readA then
operand_A_ieee <= data_in;
end if;
-- needed if pipelined core
--if next_state = addAB then
--pipeline_wr_status <= "1" & pipeline_wr_status(pipeline_depth-1 downto 1);
--else
--pipeline_wr_status <= "0" & pipeline_wr_status(pipeline_depth-1 downto 1);
--end if;
end if;
end process;
-- wr_en flag has beem moved out of the case/process below, for simplicity
wr_en <= '1' when state = addAB else '0';
--wr_en <= pipeline_wr_status(0);
-- TODO: add rst signal as input to the state machine
CL: process(rst, state, in_fifo_empty, out_fifo_full)
begin
case (state) is
when start =>
if rst = '1' then
next_state <= start;
rd_en <= '0';
else
if in_fifo_empty = '1' then
next_state <= start;
rd_en <= '0';
else
next_state <= readA;
rd_en <= '1';
end if;
end if;
when readA =>
if rst = '1' then
next_state <= start;
rd_en <= '0';
else
if in_fifo_empty = '1' then
next_state <= waitB;
rd_en <= '0';
else
next_state <= addAB;
rd_en <= '1';
end if;
end if;
when waitB =>
if rst = '1' then
next_state <= start;
rd_en <= '0';
else
if in_fifo_empty = '1' then
next_state <= waitB;
rd_en <= '0';
else
if out_fifo_full = '1' then
next_state <= waitB;
rd_en <= '0';
else
next_state <= addAB;
rd_en <= '1';
end if;
end if;
end if;
when addAB => -- aka readB (read of B operator happens here)
if rst = '1' then
next_state <= start;
rd_en <= '0';
else
if in_fifo_empty = '1' then
next_state <= start;
rd_en <= '0';
else
next_state <= readA;
rd_en <= '1';
end if;
end if;
when others =>
next_state <= start;
rd_en <= '0';
end case;
end process;
end Behavioral;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity core is
port (
operand_A_ieee, operand_B_ieee : in std_logic_vector(31 downto 0);
result_ieee : out std_logic_vector(31 downto 0);
clk, rst : in std_logic
);
end core;
architecture Behavioral of core is
component adder
port (
A, B: in std_logic_vector(31 downto 0);
R: out std_logic_vector(31 downto 0)
);
end component;
begin
addition: adder port map (operand_A_ieee, operand_B_ieee, result_ieee);
end Behavioral;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity adder is
port (
A, B: in std_logic_vector(31 downto 0);
R: out std_logic_vector(31 downto 0)
);
end adder;
architecture Behavioral of adder is
begin
R <= std_logic_vector(unsigned(A) + unsigned(B));
end Behavioral;
[VEREINFACHT IM VERGLEICH ZUM URSPRÜNGLICHEN, ABER NICHT MEHR RELEVANT - SIEHE SPÄTERE BEARBEITUNG OBEN] Ansatz für die physischen Spartan-6-I/O (Drucktasten, Schalter, LEDs):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity top is
port (
sw : in std_logic_vector(1 downto 0);
led : out std_logic_vector(7 downto 0)
);
end top;
architecture Behavioral of top is
signal a : std_logic_vector(31 downto 0) := x"3f800000";
signal b : std_logic_vector(31 downto 0) := x"3f800000";
signal r : std_logic_vector(31 downto 0);
begin
r <= std_logic_vector(unsigned(a) + unsigned(b));
led <= r(8 * (to_integer(unsigned(sw)) + 1) - 1 downto 8 * to_integer(unsigned(sw)));
end Behavioral;
# onBoard SWITCHES
NET "sw<0>" LOC = "A10"; # Bank = 0, Pin name = IO_L37N_GCLK12, Sch name = SW0
NET "sw<1>" LOC = "D14"; # Bank = 0, Pin name = IO_L65P_SCP3, Sch name = SW1
# onBoard Leds
NET "led<0>" LOC = "U18"; # Bank = 1, Pin name = IO_L52N_M1DQ15, Sch name = LD0
NET "led<1>" LOC = "M14"; # Bank = 1, Pin name = IO_L53P, Sch name = LD1
NET "led<2>" LOC = "N14"; # Bank = 1, Pin name = IO_L53N_VREF, Sch name = LD2
NET "led<3>" LOC = "L14"; # Bank = 1, Pin name = IO_L61P, Sch name = LD3
NET "led<4>" LOC = "M13"; # Bank = 1, Pin name = IO_L61N, Sch name = LD4
NET "led<5>" LOC = "D4"; # Bank = 0, Pin name = IO_L1P_HSWAPEN_0, Sch name = HSWAP/LD5
NET "led<6>" LOC = "P16"; # Bank = 1, Pin name = IO_L74N_DOUT_BUSY_1, Sch name = LD6
NET "led<7>" LOC = "N12"; # Bank = 2, Pin name = IO_L13P_M1_2, Sch name = M1/LD7
Ich kann nicht mit Sicherheit sagen, dass dies helfen wird, aber ich finde den „Pipeline“-Prozess in der „Adder“-Entität ungewöhnlich. Ich würde ein Elsif auf der steigenden Flanke der Uhr verwenden und A und B aus der Empfindlichkeitsliste entfernen.
Außerdem ist die Verwendung der steigenden Flanke von Schritt möglicherweise keine gute Idee, da es sich nicht um ein Taktsignal handelt. Eine alternative Lösung wäre, Folgendes zu tun:
process(clk)
begin
if rising_edge(clk) then
step_r <= step;
if step = '1' and step_r='0' then -- Finds rising edge of step
<Logic>
end if;
end if;
end process;
Inzwischen habe ich herausgefunden, was das Problem war. Grundsätzlich hat es mit byteweiser Endianness zu tun - dh xillybus wird die Bytes in einem 32-Bit-Wert in umgekehrter Reihenfolge darstellen, in der sie in die Gerätedatei geschrieben wurden (und beim Schreiben vom Kern auf die gleiche Weise wieder umkehren). der Wirt).
Weitere Einzelheiten finden Sie unter: https://forums.xilinx.com/t5/Implementation/Implemented-simple-binary-adder-returns-incorrect-result/mp/689491/highlight/false#M15227
Martin Zabel