Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
15 years ago

multicycle instruction FSM with nios and the done variable

I have been trying for weeks to figure out how the done variable works and it seems like it has no effect whatsoever on the program. Can anyone explain how it works.

Here's an example i've been working on:

if (reset = '1') then

state <= s0;

ELSIF (clk'EVENT AND clk = '1') THEN

CASE state IS

WHEN s0 =>

IF (start = '1' AND n = '0') THEN

io_148194546 <= dataa;

io_277277265 <= datab;

state <= s0;

done <= '1';

ELSIF (start = '1' AND n = '1') THEN

io_109970892 <= dataa;

io_19111827 <= datab;

state <= s1;

done <= '1';

ELSE

state <= s0;

done <= '0';

END IF;

WHEN s1 =>

result <= io_1298736395;

done <= '1';

state <= s0;

WHEN OTHERS =>

report "Invalid State";

END CASE;

END IF;

END PROCESS;

When I do something like:

ALT_CI_CI_HARDWARE_INST(0,2,4);

y = ALT_CI_CI_HARDWARE_INST(1,5,8);

i can't the result from the past operation in y. So if i want to get the actualy value of y, i need to do something like

ALT_CI_CI_HARDWARE_INST(0,2,4);

y = ALT_CI_CI_HARDWARE_INST(1,5,8);

y = ALT_CI_CI_HARDWARE_INST(1,5,8);

Thanks

8 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Here's the whole code. To summarize last post:

    Have to do y = ci(1,x,y) twice to get the result. Otherwise I get the result from the alst operation.

    
    -- Generated VHDL code to implement Custom Instructions
    -- CREATED: Thu Dec 02 10:20:48 EST 2010
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    ENTITY CI_HARDWARE IS
    PORT    (    SIGNAL clk        :    IN    STD_LOGIC;
                SIGNAL reset    :    IN    STD_LOGIC;
                SIGNAL clk_en    :    IN     STD_LOGIC;
                SIGNAL start    :    IN    STD_LOGIC;
                SIGNAL done        :    OUT STD_LOGIC;
                SIGNAL dataa    :    IN     STD_LOGIC_VECTOR(31 DOWNTO 0);
                SIGNAL datab    :    IN     STD_LOGIC_VECTOR(31 DOWNTO 0);
                SIGNAL result    :    OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
                SIGNAL n        :    IN    STD_LOGIC
            );
    END CI_HARDWARE;
    ARCHITECTURE behavior OF CI_HARDWARE IS
    TYPE state_type is (s0,s1);
     SIGNAL STATE    :    state_type;
    SIGNAL io_148194546    :    STD_LOGIC_VECTOR(31 DOWNTO 0);
    SIGNAL io_277277265    :    STD_LOGIC_VECTOR(31 DOWNTO 0);
    SIGNAL io_109970892    :    STD_LOGIC_VECTOR(31 DOWNTO 0);
    SIGNAL io_19111827    :    STD_LOGIC_VECTOR(31 DOWNTO 0);
    SIGNAL io_1556901833    :    STD_LOGIC_VECTOR(31 DOWNTO 0);
    SIGNAL io_1685984552    :    STD_LOGIC_VECTOR(31 DOWNTO 0);
    SIGNAL io_1298736395    :    STD_LOGIC_VECTOR(31 DOWNTO 0);
    COMPONENT lpm_add_sub
         GENERIC    (    lpm_direction        :    STRING;
                    lpm_hint            :    STRING;
                    lpm_representation    :    STRING;
                    lpm_type             :    STRING;
                    lpm_width            :    NATURAL
                );
        PORT     (    dataa    :    IN STD_LOGIC_VECTOR(31 DOWNTO 0);
                    datab    :    IN STD_LOGIC_VECTOR(31 DOWNTO 0);
                    result    :    OUT STD_LOGIC_VECTOR(31 DOWNTO 0)
                );
    END COMPONENT;
    COMPONENT lpm_mult
        GENERIC (    lpm_hint            :    STRING;
                    lpm_representation     :    STRING;
                    lpm_type            :    STRING;
                    lpm_widtha            :    NATURAL;
                    lpm_widthb            :    NATURAL;
                    lpm_widthp            :    NATURAL
                );
        PORT    (    dataa    :    IN STD_LOGIC_VECTOR(31 DOWNTO 0);
                    datab    :    IN STD_LOGIC_VECTOR    (31 DOWNTO 0);
                    result    :    OUT STD_LOGIC_VECTOR(31 DOWNTO 0)
                );
    END COMPONENT;
    BEGIN
    lpm_sub_0    :    lpm_add_sub
        GENERIC MAP     (    lpm_direction        =>    "SUB",
                            lpm_hint             =>    "ONE_INPUT_IS_CONSTANT=NO, CIN_USED=NO",
                            lpm_representation    =>    "SIGNED",
                            lpm_type            =>    "LPM_ADD_SUB",
                            lpm_width            =>    32
                        )
        PORT MAP    (io_148194546, io_277277265, io_1556901833);
    lpm_mul_0    :    lpm_mult
        GENERIC MAP     (    lpm_hint            =>    "MAXIMIZE_SPEED=5",
                            lpm_representation    =>    "SIGNED",
                            lpm_type            =>    "LPM_MULT",
                            lpm_widtha            =>    16,
                            lpm_widthb            =>    16,
                            lpm_widthp            =>    32
                        )
        PORT MAP    (io_1685984552, io_1556901833, io_1298736395);
    lpm_add_0    :    lpm_add_sub
        GENERIC MAP     (    lpm_direction        =>    "ADD",
                            lpm_hint             =>    "ONE_INPUT_IS_CONSTANT=NO, CIN_USED=NO",
                            lpm_representation    =>    "SIGNED",
                            lpm_type            =>    "LPM_ADD_SUB",
                            lpm_width            =>    32
                        )
        PORT MAP    (io_109970892, io_19111827, io_1685984552);
    PROCESS (reset, clk)
    BEGIN
    if (reset = '1') then
    state <= s0;
        ELSIF (clk'EVENT AND clk = '1') THEN
            CASE state IS
                WHEN s0 =>
                    IF (start = '1' AND  n = '0') THEN
                        io_148194546 <= dataa;
                        io_277277265 <= datab;
                        state <= s0;
                        done <= '1';
                    ELSIF (start = '1' AND  n = '1') THEN
                        io_109970892 <= dataa;
                        io_19111827 <= datab;
                        state <= s1;
                        done <= '1';
                    ELSE
                        state <= s0;
                        done <= '0';
                    END IF;
                WHEN s1 =>
                    result <= io_1298736395;
                    done <= '1';
                    state <= s0;
                WHEN OTHERS =>
                    report "Invalid State";
            END CASE;
        END IF;
    END PROCESS;
    END behavior;
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The timing of the done bit is probably off. I recommend simulating the instruction by itself so that you'll be able to see the behavior of the done bit. If nothing shows up as wrong then try simulating the system and seeing how it behaves hooked up to the Nios II core.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I've been testing it on a DE0 board using a NIOS 2/e core with the custom instruction added. Out of testing it on the board, nothing happens if i remove it completely, have it all 0s, have it all 1s, it's like the done bit doesn't do anything at all...

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Running it in hardware isn't going to tell you what the problem is. The done bit tells the processor when to complete the instruction and latch the result.

    Judging by the statemachine it looks like done bit is stuck high. Again a simulation would catch this easily.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    oops, i posted the wrong version of the FSM code. the only diff is that i have done <= '0' in the n=1 case in state s0. The simulation also works as I expect it to, an image of it is included at the bottom. But if I run the code on a nios II core on the DE0 board, it doesn't work. The results are delayed as described above with the same code.

    here's the good version of the code:

    
    PROCESS (reset, clk)
    BEGIN
    if (reset = '1') then
    state <= s0;
        ELSIF (clk'EVENT AND clk = '1') THEN
            CASE state IS
                WHEN s0 =>
                    IF (start = '1' AND  n = '0') THEN
                        io_148194546 <= dataa;
                        io_277277265 <= datab;
                        state <= s0;
                        done <= '1';
                    ELSIF (start = '1' AND  n = '1') THEN
                        io_109970892 <= dataa;
                        io_19111827 <= datab;
                        state <= s1;
                        done <= '0';
                    ELSE
                        state <= s0;
                        done <= '1';
                    END IF;
                WHEN s1 =>
                    result <= io_1298736395;
                    done <= '1';
                    state <= s0;
                WHEN OTHERS =>
                    report "Invalid State";
            END CASE;
        END IF;
    END PROCESS;
    END behavior;
    
    http://skiareatrailmaps.com/images/simulation.JPG
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Start shouldn't be asserted for more than one clock cycle. So you should see a start strobe with a valid dataa and datab input, then when your custom instruction is complete you preset the valid data output with the done signal asserted.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello, thanks for helping

    If i put start=1 just for one clock cycle, there is no result given in the simulation. If I put start for both of the 2 sets of inputs (so 2 cycles), i get the results i expect as shown in the image below (Fig 1). Maybe I don't have the SOPC set up correctly.

    -I have a NIOS2/e core to which i added the custom instruction as a CI slave and didn't change any of the settings there. Maybe there needs to be a variable in "Clock Cycles" when i add the CI as shown in Fig2.

    -on chip memory

    -sysid

    -jtag uart

    As i said, the CI works from NIOS in the c program, but the result is delayed by a call, so i have to call (1,x,y) twice to get the result.

    http://skiareatrailmaps.com/images/simulation2.JPG

    http://skiareatrailmaps.com/images/compoment_editor.JPG

    Also, tried changing the code to this, but no change. Don't know if I understood what you meant.

     if (reset = '1') then
    state <= s0;
    	ELSIF (clk'EVENT AND clk = '1') THEN
    		CASE state IS
    			WHEN s0 =>
    				IF (start = '1' AND  n = '0') THEN
    					io_148194546 <= dataa;
    					io_277277265 <= datab;
    					state <= s0;
    					done <= '1';
    				ELSIF (start = '1' AND  n = '1') THEN
    					io_109970892 <= dataa;
    					io_19111827 <= datab;
    					state <= s1;
    					done <= '0';
    				ELSE
    					state <= s0;
    					done <= '1';
    				END IF;
    			WHEN s1 =>
    				result <= io_1298736395;
    				done <= '1';
    				state <= s0;
    			WHEN OTHERS =>
    				report "Invalid State";
    		END CASE;
    	END IF;
    END PROCESS; 

    Thanks again!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    But the Nios II custom instruction master will only assert 'start' for one clock cycle. You pasted an image from component editor that shows this so if you attempt to simulate with the start signal asserted for longer than that you are not even mimicking what the processor will drive into the custom instruction which seems like a waste of time to do.

    For more details: http://www.altera.com/literature/ug/ug_nios2_custom_instruction.pdf

    Page 12-13 describe the timing of a multicycle custom instruction.