Reusing registers in VHDL FSM

Iniciado por Darian, 3 Julio 2019, 17:22 PM

0 Miembros y 1 Visitante están viendo este tema.

Darian

Hello,

I need to write a Finite State Machine (FSM) in VHDL code and  want to have several computations being processed at the same time (a standard pipeline). In every state I have several operations to be calculated and I employ registers for the result of each one. I strongly need to reuse these registers, for example: Register 1 is filled in State 1 (as a result of a multiplication) and it is used in the State 2 and State 3 (as parameter of other operations), then in the State 4, I want to save a new operation result (another multiplication) in Register 1 reusing it.

My code works in Simulation in Xilinx Vivado 2019, but when I implement the desing in a real FPGA (Basys 3 Artix-7) it doesn't work. I realized that the problem is that the correct values are not saved when I reuse the registers. Sometimes, the first time I reuse them, they keep the correct value, but already in the second reuse in later FSM states, the stored values are not correct, I mean, they do not correspond to the result of the operation that I am trying to save in the register.

Next, an example of my FSM design:

Código (vhdl) [Seleccionar]

LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.ALL;

ENTITY test1_arith IS
GENERIC (
    ap_bit_width : positive := 4;
    ap_latency : positive := 2
);
PORT (
    I1 : IN STD_LOGIC_VECTOR(ap_bit_width - 1 downto 0);
    I2 : IN STD_LOGIC_VECTOR(ap_bit_width - 1 downto 0);
    I3 : IN STD_LOGIC_VECTOR(ap_bit_width - 1 downto 0);
    O1 : OUT STD_LOGIC_VECTOR(ap_bit_width - 1 downto 0);
    ap_clk : IN STD_LOGIC;
    ap_rst : IN STD_LOGIC;
    ap_start : IN STD_LOGIC;
    ap_done : OUT STD_LOGIC;
    ap_idle : OUT STD_LOGIC;
    ap_ready : OUT STD_LOGIC
);
END;

ARCHITECTURE test1_arith_arch OF test1_arith IS
    ATTRIBUTE CORE_GENERATION_INFO : STRING;
    ATTRIBUTE CORE_GENERATION_INFO OF test1_arith_arch : ARCHITECTURE IS "Test,VHDLbyMOEA,{HLS_SYN_LAT=2}";
    CONSTANT ap_const_logic_1 : STD_LOGIC := '1';
    CONSTANT ap_const_logic_0 : STD_LOGIC := '0';
    TYPE state IS (state_1,state_2,state_3);
    SIGNAL state_present: state;
    SIGNAL state_future: state;
    SIGNAL Flag: Integer:=0;
     --Signal RF : STD_LOGIC_VECTOR_array;
    FUNCTION ALU ( Op: IN integer range 0 TO 23;
     A, B: IN STD_LOGIC_VECTOR (ap_bit_width - 1 downto 0) )
    RETURN std_logic_vector is variable Result : std_logic_vector(ap_bit_width - 1 downto 0);       

    variable A_int: Integer:=0;
    variable B_int: Integer:=0;
    variable Result_int: Integer:=0;
    begin
    A_int := to_integer(unsigned(A));
    B_int := to_integer(unsigned(B));
    With Op Select Result_int:=
        to_integer(unsigned(NOT A)) When 0,
        to_integer(unsigned(A AND B)) When 1,
        to_integer(unsigned(A OR B)) When 2,
        to_integer(unsigned(A NAND B)) When 3,
        to_integer(unsigned(A NOR B)) When 4,
        to_integer(unsigned(A XOR B)) When 5,
        to_integer(unsigned(A XNOR B)) When 6,
        (A_int + B_int) When 7,
        (A_int - B_int) When 8,
        (A_int * B_int) When 9,
        (A_int / B_int) When 10,
        ABS(A_int) When 11,
        (A_int ** B_int) When 12,
        (A_int MOD B_int) When 13,
        to_integer(unsigned(A) & unsigned(B)) When 14,
        to_integer(unsigned(A) SLL B_int) When 15,
        to_integer(unsigned(A) SRL B_int) When 16,
        to_integer(unsigned(A) SLA B_int) When 17,
        to_integer(unsigned(A) SRA B_int) When 18,
        to_integer(unsigned(A) ROL B_int) When 19,
        to_integer(unsigned(A) ROR B_int) When 20,
        to_integer(unsigned(A) & unsigned(B)) When 21,
        to_integer(unsigned(A) & unsigned(B)) When 22,
                 0   When others;
    return STD_LOGIC_VECTOR (TO_UNSIGNED (Result_int, (ap_bit_width)));
    END FUNCTION;

    SHARED VARIABLE R1:std_logic_vector(ap_bit_width - 1 downto 0);   


    BEGIN

    OP_FSM : PROCESS (state_present)

     BEGIN
    CASE state_present IS

    WHEN state_1=>
    R1 := ALU(Op => 7 ,A => I1,B => I2);
    Flag<=1;
    IF (Flag=1) THEN
    state_future <= state_2;
    END IF;

    WHEN state_2=>
    R1:= ALU(Op => 7 ,A => R1, B => I3);
    Flag<=2;
    IF (Flag=2) THEN
    state_future <= state_3;
    END IF;

    WHEN state_3=>
    O1<= ALU(Op => 7 ,A => R1,B => "0001");
    Flag<=3;
    IF (Flag=3) THEN
    state_future <= state_1;
    END IF;
    END CASE;
    END PROCESS OP_FSM;

    CLK_FSM : PROCESS (ap_clk)
    BEGIN
    IF (ap_clk = '1' AND ap_clk'EVENT) THEN
    state_present <= state_future;
    END IF;
    END PROCESS CLK_FSM;

END test1_arith_arch;


In this case, I want to reuse R1 and it works well in Simulation with Xilinx Vivado (1 + 4 + 0 + 1 = 6).

Unfortunately, in the Basys 3 FPGA Artix-7 I don't get the correct results. In the Case 10 in a FPGA, it should get 6 (1 + 4 + 0 + 1) as result, but it gets 14 instead.

In the tests that I have been doing I realized that it works better when before assigning a new value in the registry the value of the record is made zero before reassigning a value, for example:

Código (vhdl) [Seleccionar]
WHEN state_3=>
    R4<="0000"
    IF( R4 = "0000") then
    R4<= ALU(Op => 7 ,A=> R2,B=> R3, C =>"0000");
    Flag <=3;
    IF (Flag =3) THEN
    state_future <= state_4;
END IF;
END IF;


Using this form I can reuse a register once, the second time I want to reassign a value to the register, incorrect values are shown in the output.

I declarated the registers as SHARED VARIABLE and SIGNALS and I have the same problem with both.

I appreciate any suggestion or idea, thanks a lot.