EDICIÓN POSTERIOR:
1. También investigué visualmente el dispositivo Kintex7 después de la implementación (es decir, interconexiones, etc.) y todo se ve bien; no hay conexiones que indiquen que las cosas no estarían bien (por supuesto, no volví al principio). entradas, ya que asumo que si el bucle invertido basado en 2-FIFO funciona, sería el sumador el que está roto de alguna manera).
Además, me encontré con este registro de respuestas de Xilinx . Traté de aplicar la solución sugerida, pero no pareció funcionar.
2. Para el segundo enfoque (entrada manual en Spartan6), me di cuenta de que el problema era un interruptor defectuoso que no establecería correctamente el valor de entrada a menos que se tuviera cuidado. He probado cuidadosamente de nuevo y esta vez obtuve el valor correcto. Sin embargo, cambié ese diseño para tomar las entradas de ROM/LUT y mostrar un byte a la vez, dependiendo de los interruptores de selección dados como entradas. Ya no hay reloj involucrado. El problema con el proyecto inicial basado en Vivado persiste, lo que me lleva a creer que podría ser un problema de síntesis/implementación/hardware defectuoso.
MENSAJE ORIGINAL:
Tengo un diseño PCIe basado en xillybus que está destinado a volverse más complejo, pero por ahora, de forma incremental, solo lee pares de valores de 32 bits de un FIFO de entrada de 32 bits conectado a xillybus y los suma, escribiéndolos en un FIFO de salida de 32 bits conectado a xillybus.
Ahora, el problema que veo es el siguiente:
NOTA 1: la forma de onda de salida de la simulación de comportamiento (nivel RTL, presíntesis) devuelve valores correctos, es la implementación real en la placa la que parece tener uno o más bits invertidos ( opuesto al valor esperado, que es el mismo que el resultado de la simulación)
NOTA 2: Yo, por ejemplo, uso los valores 0x3F800000
y 0x3F800000
(sí, el doble del mismo valor), que sumados poco a poco deberían sumar 0x7F000000
- mencionaré a continuación cuál fue el resultado (incorrecto) en cada escenario:
0x7E000100
(recuerde, la prueba de bucle invertido funciona)0x6F00000
(más cercano, ya que solo hay un poco de error, pero aún no es suficiente)Tenga en cuenta que no recibo quejas sobre violaciones de restricciones de tiempo, y de todos modos he intentado muchas formas de concentrarme en el problema (es decir, filtrar algunas posibilidades), pero no llegué a ninguna conclusión. Para que conste, incluso transformé el sumador simple en una canalización de 2 niveles, para "garantizar" que haya suficiente tiempo para calcular el resultado, pero el resultado fue el mismo (incorrecto).
Aparentemente, no puedo ejecutar la simulación funcional o temporal posterior a la síntesis o posterior a la implementación, ya que aparece un error molesto que dice
ERROR: [VRFC 10-716] el puerto formal o del modo fuera no se puede asociar con el puerto real pcie_perst_b_ls del modo en [...]
Tenga en cuenta que estoy ejecutando Vivado 2014.2 (que es un poco antiguo, pero ¿sería ese realmente el problema?)
Debajo, el código para los 2 enfoques (E/S impulsada por PCIe basada en xillybus y E/S física simple). Lo siento, no pude formatearlo mejor:
Enfoque para las E/S basadas en Kintex-7 PCIe:
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;
[SIMPLIFICADO EN COMPARACIÓN CON EL INICIAL, PERO YA NO ES RELEVANTE - VÉASE LA EDICIÓN POSTERIOR ANTERIOR] Enfoque para la E/S física del Spartan-6 (botones pulsadores, interruptores, LED):
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
No puedo decir con certeza que esto ayudará, pero encuentro que el proceso de "canalización" en la entidad "sumador" es inusual. Usaría un elsif en el borde ascendente del reloj y eliminaría A y B de la lista de sensibilidad.
Además, usar el flanco ascendente del paso puede no ser una buena idea ya que no es una señal de reloj. Una solución alternativa sería hacer algo así:
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;
Mientras tanto, he descubierto cuál era el problema. Básicamente, tiene que ver con el endianismo de los bytes, es decir, xillybus presentará los bytes en un valor de 32 bits en el orden inverso al que se escribieron en el archivo del dispositivo (y volteará nuevamente de la misma manera al escribir desde el núcleo a el anfitrión).
Para obtener más detalles, consulte: https://forums.xilinx.com/t5/Implementation/Implemented-simple-binary-adder-returns-incorrect-result/mp/689491/highlight/false#M15227
Martín Zabel