Fork/Join in VHDL ?

Why OSVVM™? Forums VHDL Fork/Join in VHDL ?

Tagged: ,

This topic contains 2 replies, has 2 voices, and was last updated by Avatar of Steve Chan Steve Chan 7 years, 2 months ago.

Viewing 3 posts - 1 through 3 (of 3 total)
  • Author
    Posts
  • #357
    Avatar of Steve Chan
    Steve Chan
    Member

    *Hi

    Is there a open-source package to emulate Fork/join in VHDL? If so, a example is greatly appreciated.

    Many thanks in advance

     

    #358

    Hi Steve,

    You cannot get exact emulation of Verilog style fork..join, i.e. creation of separate threads inside the process. You can create separate processes representing threads and synchronize them with the main process instead. Most popular (but not the only one) method to do synchronization is via custom resolved types.

    I’m including sample package defining types and procedures for synchronization, followed by short example of usage. Feel free to examine and modify it.

     -- 'Forking' VHDL package with usage example
     -- Created by Jerry Kaczynski in 2008
     -- Open source - free to use and modify as long as this header/proper credits are given
     package Forking is
         -- data type describing states of forking processes
         type prc_state is (stop, run, start);
         -- vectorized 'prc_state'; required by resolution functions
         type prc_state_array is array(natural range<>) of prc_state;
         -- resolution function for modeling 'fork-join_all' 
         function resolve_all(a : prc_state_array) return prc_state;
         -- resolved subtype of 'prc_state' for modeling 'fork-join_all'
         subtype prc_join_all is resolve_all prc_state;
         -- resolution function for modeling 'fork-join_any' 
    
         function resolve_any(a : prc_state_array) return prc_state;
    
         -- resolved subtype of 'prc_state' for modeling 'fork-join_any'
         subtype prc_join_any is resolve_any prc_state;
         -- procedure for initializing fork; must be used by all 
         -- threads, even the parent; data type of the argument
         -- decides if 'join_all' or 'join_any' will be used
         procedure fork(signal s: inout prc_state);
         -- procedure joining all threads; must be called
         -- at the end of each thread
         procedure join_all(signal s: inout prc_join_all);
         -- procedure joining child threads of 'fork-join_any';
         -- should not be called in parent thread!
         procedure join_any(signal s: inout prc_join_any);
         -- procedure waiting for any forked thread to complete;
         -- should be called ONLY in parent thread
         procedure wait_for_any(signal s: inout prc_join_any);
     end package Forking;
     
     package body Forking is
         function resolve_all(a : prc_state_array) return prc_state is
          variable isStart, isStop : Boolean := True;        
         begin
             for i in a'range loop
                 if a(i)/=start then
                     isStart := False;
                 end if;
                 if a(i)/=stop then
                     isStop := False;
                 end if;
             end loop;
             if isStart then
                 return start;
             elsif isStop then
                 return stop;
             else
                 return run;
             end if;
         end function resolve_all;
         
         function resolve_any(a : prc_state_array) return prc_state is
          variable isStart, isRun : Boolean := True;        
         begin
             for i in a'range loop
                 if a(i)/=start then
                     isStart := False;
                 end if;
                 if a(i)/=run then
                     isRun := False;
                 end if;
             end loop;
             if isStart then
                 return start;
             elsif isRun then
                 return run;
             else
                 return stop;
             end if;
         end function resolve_any;
         
         procedure fork(signal s: inout prc_state) is    
         begin
             s <= start; 
             wait until s=start;
             s <= run;
         end;
         
         procedure join_all(signal s: inout prc_join_all) is    
         begin
             s <= stop; 
             wait until s=stop;
         end;    
                 
         procedure join_any(signal s: inout prc_join_any) is    
         begin
             s <= stop; 
             wait until s=stop;
         end;
         
         procedure wait_for_any(signal s: inout prc_join_any) is    
         begin
             wait until s=stop;
         end;    
                 
     end package body Forking;
     
     use work.forking.all;
     
     entity Paternal is
     end Paternal;
     
     architecture Behavior of Paternal is
     signal ctrl1 : prc_join_all;
     signal ctrl2 : prc_join_any;
     begin
         father: process
         begin
             wait for 10 ns;
             report "Father says: We should be forking right after this..." severity warning;
             -- 'father' spawns three child processes here and continues
             -- to run itself till all 'join_all' procedures complete
             fork(ctrl1); 
             report "They are working...";
             -- time to wait for    all child processes to complete 
             join_all(ctrl1);
             report "Now joined after all that forking!";
             wait for 10 ns;
             report "Father says: Let's begin the race..." severity warning;
             -- now 'father' spawns two child processes using signal
             -- 'ctrl2' of 'prc_join_any' type; the first child process
             -- to execute 'join_any' procedure will pass control back
             -- to the statement right after 'wait_for_any'
             fork(ctrl2);
             wait_for_any(ctrl2);
             report "Now I know which horse is the fastest!";
             wait;
         end process    father;
         
         -- 'son1','son2' and 'son3' processes are forked using 'ctrl1' signal
         -- of 'prc_join_all' type, which means that the last to complete
         -- execution will return control to the parent    process
         son1: process
         begin
             fork(ctrl1);
             report "Son1 at work!";
             wait for 10 ns;
             report "Son1 done!!!";
             join_all(ctrl1);
             wait;
         end process son1;
         
         son2: process
         begin
             fork(ctrl1);
             report "Son2 at work!";
             wait for 20 ns;
             report "Son2 done!!!";
             join_all(ctrl1);
             wait;
         end process son2;
         
         son3: process
         begin
             fork(ctrl1);
             report "Son3 at work!";
             wait for 30 ns;
             report "Son3 done!!!";
             join_all(ctrl1);
             wait;
         end process son3;
     
         -- 'horse1' and 'horse2' processes are forked using 'ctrl2' signal
         -- of 'prc_join_any' type, which means that the first to complete
         -- execution will return control to the parent process
         horse1: process
         begin
             fork(ctrl2);
             report "Horse1 running!";
             wait for 15 ns;
             report "Horse1 arrived!!!";
             join_any(ctrl2);
             wait;
         end process horse1;
         
         horse2: process
         begin
             fork(ctrl2);
             report "Horse2 running!";
             wait for 12 ns;
             report "Horse2 arrived!!!";
             join_any(ctrl2);
             wait;
         end process horse2;
         
     end Behavior;
     

    Thank you,

    Jerry

    #362
    Avatar of Steve Chan
    Steve Chan
    Member

    *Hi Jerry

    Thank you for the code.
    This is most helpful. I will try it out.
    I am so gladful to find this community here for the VHDL development.

    Thanks

Viewing 3 posts - 1 through 3 (of 3 total)

You must be logged in to reply to this topic.