UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor sebyspi
Visitor
1,010 Views
Registered: ‎02-09-2018

VHDL - my FSM does not advance when in a certain state

I'm trying to implement a circuit for a digital signature (RSA) on a FPGA Digilent Basys. I ended to write down all the components and the top level entity. The Control Unit is formed by a Finit State Machine that controls the whole circuit. But when I load it on my Basys, it seems to freeze in the State "V_wait_sign". I can say that because how you can see in the FSM, in the state "V_wait_sign" I puts Leds out to "00100", so just the Led2 is On.

Below the code of the Top Level Entity and the FSM:

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;  
entity FirmaDigitale is
    Port ( Clock : in  STD_LOGIC;
           Buttons : in  STD_LOGIC_VECTOR (3 downto 0);
           Switches : in  STD_LOGIC_VECTOR (7 downto 0);
           Leds : out  STD_LOGIC_VECTOR (7 downto 0);
           Cathodes : out  STD_LOGIC_VECTOR (7 downto 0);
           Anodes : out  STD_LOGIC_VECTOR (3 downto 0));
end FirmaDigitale;

architecture Structural of FirmaDigitale is

    component Comparator32
    Generic(width : Positive := 32);
    Port ( a : in  STD_LOGIC_VECTOR (width-1 downto 0);
           b : in  STD_LOGIC_VECTOR (width-1 downto 0);
          Clock  : in  STD_LOGIC;
          Comp_en : in  STD_LOGIC;  -- 1 attivo
           equal : out  STD_LOGIC;
          Notequal : out  STD_LOGIC);
    end component;

    component Decoder_2_4
    Port ( i : in  STD_LOGIC_VECTOR (1 downto 0);
           o : out  STD_LOGIC_VECTOR (3 downto 0));
    end component;

    component Decoder_Seven_segm
    Port ( Ing : in  STD_LOGIC_VECTOR (3 downto 0);
           Cathodes : out  STD_LOGIC_VECTOR (6 downto 0));
    end component;

    component FSM_RSA
    Port ( 
        Clock : in  STD_LOGIC;          -- Clock
        --in

        Start_sign : in  STD_LOGIC; --start sign
        Load : in  STD_LOGIC;          --load 8 bits
        Verify : in  STD_LOGIC;         --start verify signature
        Done : in  STD_LOGIC;           --end message
        Exp_Done : in  STD_LOGIC;       --end exp operation
        Count_hit :in STD_LOGIC;        --signature load
        Count_eq :in STD_LOGIC;         --
        Count_neq :in STD_LOGIC;        --
        --control

        Enable_Hash : out STD_LOGIC;        -- Enable hash '0' attivo         (2colpi)
        Enable_Exp : out STD_LOGIC;     -- Enable exp '1' attivo
        Enable_RegExp : out STD_LOGIC;  -- Enable RegExp '0' attivo
        Enable_sign_reg : out STD_LOGIC; -- Enable sign_reg '0' attivo
        Enable_comp : out STD_LOGIC;        -- Enable Comparator '1' attivo
        Enable_Disp : out STD_LOGIC_VECTOR(3 downto 0);         -- Enable 7segm '0' attivo  

        Leds_step : out STD_LOGIC_VECTOR(4 downto 0);
        Mux_sel : out STD_LOGIC;            -- 1 per verifica, 0 per firma
        Mux_disp : out STD_LOGIC;           -- 1 MSB, 0 LSB
        Reset_State : out STD_LOGIC     -- Reset '0' attivo
        );
    end component;

    component HashFunction
    Generic( width : integer := 32; width_reg : integer := 8);
    Port ( CharacterByte : in  STD_LOGIC_VECTOR(width_reg-1 downto 0);
          Clock : in  STD_LOGIC;
           Reset : in  STD_LOGIC; --0 attivo
          Reg_en : in STD_LOGIC; --0 attivo
           Digest : out  STD_LOGIC_VECTOR(width-1 downto 0)           
          );
    end component;

    component Mux_2n_1n
    Generic(width : integer := 8);
    Port ( a : in  STD_LOGIC_VECTOR(width-1 downto 0);
           b : in  STD_LOGIC_VECTOR(width-1 downto 0);
           s : in  STD_LOGIC;
           o : out  STD_LOGIC_VECTOR(width-1 downto 0));
    end component;

    component RAsync_2UpNCount_UpCounter
    Generic (width : integer := 2);
    Port ( clock : in  STD_LOGIC;      -- Clock
         reset : in  STD_LOGIC;    -- Segnale di reset 0 attivo
         en : in  STD_LOGIC;       -- Segnale di enable 1 attivo
         count : out  STD_LOGIC_VECTOR (width-1 downto 0) := (others => '0'));  -- conteggio attuale
    end component;

    component SignReg
    Generic( width : integer := 32; width_reg : integer := 8 );
    Port ( SignatureByte : in  STD_LOGIC_VECTOR (width_reg-1 downto 0);
           Reset : in  STD_LOGIC;
          Count_En : in  STD_LOGIC;
           Clock : in  STD_LOGIC;
          hit : out STD_LOGIC;
       Signature : out  STD_LOGIC_VECTOR (width-1 downto 0));
    end component;

    component exponentiator
    Generic (n : integer := 32);
    Port (
        x, y, m: in std_logic_vector(n-1 downto 0);
        z: inout std_logic_vector(n-1 downto 0);
        clk, reset, start: in std_logic;
        done: out std_logic 
    );
    end component;

    component display_7_segments
    Generic(
            clock_frequency_in : integer := 50000000;
            clock_frequency_out : integer := 50000000
            );
   Port (  clock : in  STD_LOGIC;
           reset_n : in  STD_LOGIC;
           digits : in  STD_LOGIC_VECTOR (15 downto 0);
           enable : in  STD_LOGIC_VECTOR (3 downto 0);
           dots : in  STD_LOGIC_VECTOR (3 downto 0);
           anodes : out  STD_LOGIC_VECTOR (3 downto 0);
           cathodes : out  STD_LOGIC_VECTOR (7 downto 0));
    end component;

    component Debouncer_xilinx is 
    Port ( CLK : in  STD_LOGIC; 
           Sig : in  STD_LOGIC; 
           Deb_Sig : out  STD_LOGIC); 
    end component;

    signal temp_exp_done, temp_enable_exp, sel_muxTo_display,   temp_count_hit, temp_sel_EncDec, temp_comp_en, temp_eq, temp_not_eq,   temp_en_RegExp : STD_LOGIC := '0';
    signal temp_reset_state, temp_enable_hash, temp_en_SignReg : STD_LOGIC := '1';
    signal temp_digest, temp_exp_out, temp_key, temp_sign, Exp_mux_out, RegExp_out : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
    signal temp_enable_disp : STD_LOGIC_VECTOR(3 downto 0) := (others => '0');
    signal temp_digits, temp_digits_to_display, temp_fin_digits : STD_LOGIC_VECTOR(15 downto 0);
    signal Start_temp, Load_temp, Verify_temp, Done_temp : STD_LOGIC;

begin

    deb_0: Debouncer_xilinx 
        port map(
            CLK => Clock, 
            Sig =>  Buttons(0), 
            Deb_Sig => Start_temp 
            );

    deb_1: Debouncer_xilinx 
        port map(
            CLK => Clock, 
            Sig =>  Buttons(1), 
            Deb_Sig => Load_temp
            );

    deb_2: Debouncer_xilinx 
        port map(
            CLK => Clock, 
            Sig =>  Buttons(2), 
            Deb_Sig => Verify_temp
            );

    deb_3: Debouncer_xilinx 
        port map(
            CLK => Clock, 
            Sig =>  Buttons(3), 
            Deb_Sig => Done_temp
            );

    FSM: FSM_RSA
    Port map ( 
        Clock => Clock,
        Start_sign => Start_temp,
        Load => Load_temp,         --load 8 bits
        Verify => Verify_temp,
        Done => Done_temp,
        Exp_Done => temp_exp_done,
        Count_hit => temp_count_hit,
        Count_eq => temp_eq,
        Count_neq => temp_not_eq,
        --control

        Enable_Hash => temp_enable_hash,
        Enable_Exp => temp_enable_exp,
        Enable_RegExp => temp_en_RegExp,
        Enable_sign_reg => temp_en_SignReg,
        Enable_comp => temp_comp_en,
        Enable_Disp => temp_enable_disp,

        Leds_step => Leds(4 downto 0),
        Mux_sel => temp_sel_EncDec,
        Mux_disp => sel_muxTo_display,
        Reset_State => temp_reset_state
        );

    RegExp : entity work.Generic_RAsync_Register 
        generic map (width => 32)
        port map ( 
            D=> temp_exp_out,
            clock => Clock,
            reset => temp_reset_state,
            en => temp_en_RegExp,
            Q => RegExp_out
            );

    EncriptDecript: exponentiator
    Generic map(n => 32)
    Port map(   x => temp_key,
                y => Exp_mux_out,
                m => x"0000008F", --143, p=11, q=13; pq=143
                z => temp_exp_out,
                clk => Clock,
                reset => not temp_reset_state,
                start => temp_enable_exp,
                done => temp_exp_done
        );

    Leds(7) <= temp_exp_done;

    Mux_Enc_Dec: Mux_2n_1n
    Generic map(width => 32)
    Port map(   a => x"00000071", --113, Chiave Privata
                b => x"00000011", --17, Chiave Pubblica
                s => temp_sel_EncDec,
                o => temp_key
        );

    RegistroFirma: SignReg
    Generic map( width => 32, width_reg => 8 )
    Port map(   SignatureByte => Switches,
                Reset => temp_reset_state,
                Count_En => temp_en_SignReg,
                Clock => Clock,
                hit => temp_count_hit,
                Signature => temp_sign
        );

    Exp_mux : Mux_2n_1n generic map (width => 32)
        port map(
            a => temp_digest,
            b => temp_sign,
            s => temp_sel_EncDec,
            o => Exp_mux_out
            );

    HASH: HashFunction
    Generic map( width => 32, width_reg => 8)
    Port map(   CharacterByte => Switches,
                Clock => Clock,
                Reset => temp_reset_state,
                Reg_en => temp_enable_hash,
                Digest => temp_digest
          );

    Display: display_7_segments
    Generic map( clock_frequency_in => 50000000, clock_frequency_out => 1000 )
    Port map(   clock => Clock,
                reset_n => temp_reset_state,
                digits => temp_digits,
                enable => temp_enable_disp,
                dots => "0000",
                anodes => Anodes,
                cathodes => Cathodes
         );

    Mux_MSB_LSB: Mux_2n_1n
    Generic map(width => 16)
    Port map(   a => RegExp_out(15 downto 0),
                b => RegExp_out(31 downto 16),
                s => sel_muxTo_display,
                o => temp_digits
        );

    Compare: Comparator32
    Generic map( width => 32 )
    Port map(   a => RegExp_out,
                b => temp_sign,
                Clock => Clock,
                Comp_en => temp_comp_en,
                equal => temp_eq,
                Notequal => temp_not_eq
            );

    Leds(6) <= temp_eq;
    Leds(5) <= temp_not_eq;

end Structural;

this is the FSM instead:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity FSM_RSA is
    Port ( 
        Clock : in  STD_LOGIC;          -- Clock
        --in

        Start_sign : in  STD_LOGIC; --start sign
        Load : in  STD_LOGIC;          --load 8 bits
        Verify : in  STD_LOGIC;         --start verify signature
        Done : in  STD_LOGIC;           --end message
        Exp_Done : in  STD_LOGIC;       --end exp operation
        Count_hit :in STD_LOGIC;        --signature load
        Count_eq :in STD_LOGIC;         --
        Count_neq :in STD_LOGIC;        --
        --control

        Enable_Hash : out STD_LOGIC;        -- Enable hash '0' attivo (2colpi)
        Enable_Exp : out STD_LOGIC;     -- Enable exp '1' attivo
        Enable_RegExp : out STD_LOGIC;  -- Enable RegExp '0' attivo
        Enable_sign_reg : out STD_LOGIC; -- Enable sign_reg '0' attivo
        Enable_comp : out STD_LOGIC;        -- Enable Comparator '1' attivo
        Enable_Disp : out STD_LOGIC_VECTOR(3 downto 0);         -- Enable 7segm '0' attivo  

        Leds_step : out STD_LOGIC_VECTOR(4 downto 0);

        Mux_sel : out STD_LOGIC;            -- 1 per verifica, 0 per firma
        Mux_disp : out STD_LOGIC;           -- 1 MSB, 0 LSB
        Reset_State : out STD_LOGIC     -- Reset '0' attivo
        );

end FSM_RSA;

architecture Behavioral of FSM_RSA is

-- Definizione dell'insieme degli stati
type State is (Idle, V_wait8, S_wait8, V_Hash,V_waitReg, V_waitH, S_waitH, S_Hash, V_wait_sign, V_decrypt, V_comp, V_reg, S_encrypt, S_dispMSB, S_dispLSB);

-- Definizione dei segnali di "stato" e inizializzazione allo stato iniziale idle
signal Current_State, Next_State : State := Idle;

begin

-- Process per la gestione dell'evoluzione dello stato
state_management : process(Clock)

begin

if falling_edge(Clock) then
    Current_State <= Next_State;
else
    Current_State <= Current_State;
end if;

end process;

-- Process per la gestione della FSM
FSM : process(Current_State, Start_sign, Load, Verify, Done, Exp_Done, Count_eq, Count_neq, Count_hit)
begin

case Current_State is

  --macchina in attesa di comandi. Tutti i registri disabilitati
    when Idle => 
            Enable_Hash <= '1'; 
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '0';
            Mux_sel <= '0';
            Mux_disp <= '0';
            Leds_step <= "00000";

        if (Verify = '1') then
                Next_State <= V_wait8;
            else 
                if ( Start_sign ='1') then
                    Next_state <= S_wait8;
                    else
                        Next_state <= Idle;
                end if;
        end if;

        when S_encrypt => 
            Enable_Hash <= '1';
            Enable_Exp <= '1';  -- abilito
            Enable_RegExp <= '0';  -- abilito
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1'; 
            Mux_sel <= '0'; --decript M_h**d modn
            Mux_disp <= '0';
            Leds_step <= "00010";

            if (Exp_Done = '1') then
                    Next_State <= S_dispMSB;
                else
                    Next_state <= S_encrypt;
            end if;

        when S_dispLSB => 
            Enable_Hash <= '1';
            Enable_Exp <= '0';  
            Enable_RegExp <= '1';  
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "1111"; -- abilito
            Reset_State  <= '1'; 
            Mux_sel <= '0'; 
            Mux_disp <= '0'; --LSB

            if (Done = '1') then
                    Next_State <= Idle;
                else
                    Next_state <=S_dispLSB;
            end if;

        when S_dispMSB => 
            Enable_Hash <= '1';
            Enable_Exp <= '0';  
            Enable_RegExp <= '1';  
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "1111"; -- abilito
            Reset_State  <= '1'; 
            Mux_sel <= '0'; 
            Mux_disp <= '1'; --MSB

            if (Load = '1') then
                    Next_State <= S_dispLSB;
                else
                    Next_state <=S_dispMSB;
            end if;

        when S_waitH => 
           Enable_Hash <= '1'; --disabilito tutto
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1';
            Mux_sel <= '0';

            if( Load = '0') then
                Next_State <= S_wait8;
            else
                Next_State <= S_waitH;
            end if;


        when S_Hash => 
           Enable_Hash <= '0'; -- abilito
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1';
            Mux_sel <= '0';
            Mux_disp <= '0';

          Next_State <= S_waitH;

        when S_wait8 =>         
            Enable_Hash <= '1'; --disabilito tutto
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1';
            Mux_sel <= '0';
            Mux_disp <= '0';
            Leds_step <= "00001";

            if (Done = '1') then
                Next_State <= S_encrypt;
            else 
                if ( Load = '1') then
                    Next_state <= S_Hash;
                    else 
                        Next_state <= S_wait8;
                end if;
            end if;

        when V_comp => 
            Enable_Hash <= '1';
            Enable_Exp <= '0';  
            Enable_RegExp <= '0';
            Enable_sign_reg <= '1';
            Enable_comp <= '1';  -- abilito
            Enable_Disp <= "0000";
            Reset_State  <= '1'; 
            Mux_sel <= '1'; --decript M_h**e modn
            Mux_disp <= '0';
            Leds_step <= "10000";

            if (Count_eq = '1' OR Count_neq ='1') then
                if (Done = '1') then
                    Next_State <= Idle;
                end if;
            end if;

        when V_decrypt => 
            Enable_Hash <= '1';
            Enable_Exp <= '1';  -- abilito
            Enable_RegExp <= '0';  -- abilito
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1'; 
            Mux_sel <= '1'; --decript M_h**e modn
            Mux_disp <= '0';
            Leds_step <= "01000";

            if (Exp_Done = '1') then
                    Next_State <= V_comp;
                else
                    Next_state <= V_decrypt;
            end if;


    when V_Reg => 
           Enable_Hash <= '1'; 
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '0'; -- abilito
            Enable_comp <= '0';
            Enable_Disp <= "1111";
            Reset_State  <= '1';
            Mux_sel <= '0';
            Mux_disp <= '0';

            if( Count_hit = '1') then
                Next_State <= V_decrypt;
            else
                Next_State <= V_waitReg;
            end if;


    when V_waitReg => 
           Enable_Hash <= '1'; --disabilito tutto
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1';
            Mux_sel <= '0';
            Mux_disp <= '0';

            if( Load = '0') then
                Next_State <= V_wait_sign;
            else
                Next_State <= V_waitReg;
            end if;


    when V_wait8 =>         
            Enable_Hash <= '1'; --disabilito tutto
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1';
            Mux_sel <= '0';
            Mux_disp <= '0';

            if (Done = '1') then
                    Next_State <= V_wait_sign;
                else 
                    if ( Load = '1') then
                        Next_state <= V_Hash;
                        else 
                            Next_state <= V_wait8;
                    end if;
            end if;


    when V_Hash => 
           Enable_Hash <= '0'; -- abilito
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1';
            Mux_sel <= '0';
            Mux_disp <= '0';

          Next_State <= V_waitH;


    when V_waitH => 
           Enable_Hash <= '1'; --disabilito tutto
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1';
            Mux_sel <= '0';

            if( Load = '0') then
                Next_State <= V_wait8;
            else
                Next_State <= V_waitH;
            end if;


    when V_wait_sign => 
            Enable_Hash <= '1';  --disabilito tutto
            Enable_Exp <= '0';
            Enable_RegExp <= '1';
            Enable_sign_reg <= '1';
            Enable_comp <= '0';
            Enable_Disp <= "0000";
            Reset_State  <= '1';
            Mux_sel <= '0';
            Leds_step <= "00100";

        if (Load = '1') then -- AND Count_hit = '0') then
            Next_State <= V_reg;    
--      else
--          if (Count_hit = '1') then
--              Next_state <= V_decrypt;
            else
                Next_state <= V_wait_sign;
            --end if;
        end if; 

    end case;       
end process;
end Behavioral;

I can't understand what could be wrong. When I try the testbench, it seems to work. But tjan on the FPGA it freezes on that state. It is as if he did not receive the signal "Count Hit" from the "SignReg". But I'm not sure about that

0 Kudos
4 Replies
Scholar jmcclusk
Scholar
991 Views
Registered: ‎02-24-2014

Re: VHDL - my FSM does not advance when in a certain state

Time to read up on Vivado Debugger!    This can show you what's happening (or not happening in the actual hardware).  You'll need a JTAG cable attached to your demo board.

Don't forget to close a thread when possible by accepting a post as a solution.
0 Kudos
Highlighted
Visitor sebyspi
Visitor
963 Views
Registered: ‎02-09-2018

Re: VHDL - my FSM does not advance when in a certain state

I cannot buy a JTAG cable. Anyway, if it can help, I uploaded the whole project here.
https://drive.google.com/open?id=1bdP9O0HInMKPGZJy_6jxlVnyrGndEYGj
I edited a couple of things.. now seems to be freezed in the state "V_decrypt"

0 Kudos
Voyager
Voyager
861 Views
Registered: ‎06-20-2017

Re: VHDL - my FSM does not advance when in a certain state

The value of what you're asking here is far more expensive than a programming cable.  And if your digilent card is like all of the Digilent cards I've used, an inexpensive, simple, and ubiquitous USB cable is all that is needed.

 

But before you use chipscope or VLA, rerun your simulations (or run them if you haven't).  Make sure they are testing the conditions you expect.


I don't know if this is related to your problem, but uou'll notice a problem on line 48 of RSA.vhd.

 

Also, while I'm not a fan of two process state machines, a couple of things regarding RSA_FSM.vhd file:

 

state_management : process(Clock)

begin
	
	if falling_edge(Clock) then
		Current_State <= Next_State;
	else
		Current_State <= Current_State;
	end if;

end process;

could be more masterfully written as

state_management : process(Clock)
begin
	if falling_edge(Clock) then
		Current_State <= Next_State;
	end if;
end process;

It is a clocked process, inferring a register, so you do not need a default assignment to Current_State.

 

Also, on line 87 of the same file, you might want to make sure you have a complete sensitivity list.  I'm not checking, but that is one of the drawbacks of using a two process state machine.  If you can enable VHDL 2008, you can use the keyword ALL as the sensitivity list.

 

I'd suggest you convert your state machine to a one process state machine to avoid problems due to incomplete sensitivity lists and inferred latches. 

 

If your professor taught you to do a two process state machine, tell him that was very good advice, in 1994.  But synthesizers have evolved, and that two and three process state machines cause new VHDL users more trouble than they are worth, result in less readable code, and synthesizers do just fine with one process state machines if you pay attention to the numbers of levels of logic inferred between registers, and if you are careful with any dataflow in the state machine (it is a good idea for new users unable to estimate levels of logic to separate their dataflow from their state machines).

 

Anyway, I hope this helps.  Look at your synthesizer's user guide for examples of coding and try to mimic those examples.

Adaptable Processing coming to an IP address near you.
0 Kudos
Mentor hgleamon1
Mentor
835 Views
Registered: ‎11-14-2011

Re: VHDL - my FSM does not advance when in a certain state

This sounds like a classic unsynchronised input condition (metastable inputs).

 

How are you synchronising your external inputs to the FPGA clock? Do you meet all timing requirements?

----------
"That which we must learn to do, we learn by doing." - Aristotle
0 Kudos