Mutexes in VHDL

In the previous example, we saw how to manage simple counter state using atomic operations. For more complex state, we can use a mutex to safely access data across multiple processes.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity MutexExample is
end MutexExample;

architecture Behavioral of MutexExample is
    -- Container holds a record of counters; since we want to
    -- update it concurrently from multiple processes, we
    -- add a mutex to synchronize access.
    type CounterMap is array (0 to 1) of integer;
    type Container is record
        counters : CounterMap;
        mutex    : boolean;
    end record;
    
    signal c : Container := (counters => (0, 0), mutex => false);
    
    -- Procedure to increment a counter
    procedure inc(signal cont : inout Container; index : integer) is
    begin
        -- Wait until the mutex is available
        wait until cont.mutex = false;
        -- Lock the mutex
        cont.mutex <= true;
        -- Increment the counter
        cont.counters(index) <= cont.counters(index) + 1;
        -- Unlock the mutex
        cont.mutex <= false;
    end procedure;

begin
    -- Process to increment counter 'a'
    process
    begin
        for i in 1 to 10000 loop
            inc(c, 0);
        end loop;
        wait;
    end process;

    -- Another process to increment counter 'a'
    process
    begin
        for i in 1 to 10000 loop
            inc(c, 0);
        end loop;
        wait;
    end process;

    -- Process to increment counter 'b'
    process
    begin
        for i in 1 to 10000 loop
            inc(c, 1);
        end loop;
        wait;
    end process;

    -- Process to print the final results
    process
    begin
        wait for 1 ms;  -- Wait for other processes to complete
        report "Counter a: " & integer'image(c.counters(0));
        report "Counter b: " & integer'image(c.counters(1));
        wait;
    end process;

end Behavioral;

In this VHDL implementation, we define a Container record that holds an array of counters and a boolean mutex. The inc procedure is used to increment a specific counter in the container, using the mutex for synchronization.

We create three separate processes to increment the counters concurrently, simulating the behavior of goroutines in the original example. Two processes increment counter ‘a’ (index 0), and one process increments counter ‘b’ (index 1).

A final process waits for a short time to allow the other processes to complete, then prints the final counter values.

To run this VHDL code, you would typically use a VHDL simulator such as ModelSim or GHDL. The simulation would show the final counter values after all processes have completed their operations.

Note that VHDL is typically used for hardware description and simulation, so the concept of “running” the program is different from software languages. In a hardware context, this code would describe the behavior of a circuit that manages shared counters with mutex-based synchronization.

Next, we’ll look at implementing this same state management task using only concurrent processes and signals, which is more idiomatic in VHDL.