---------------------------------------------------------------- -- Chapter 19 Shared Variables and Protected Types ---------------------------------------------------------------- ---------------------------------------------------------------- -- 19.1 Shared Variables and Mutual Exclusion ---------------------------------------------------------------- -- Example 19.1, Page 586 type shared_counter is protected procedure reset; procedure increment ( by : integer := 1 ); impure function value return integer; end protected shared_counter; -- Example 19.1, Page 587 shared variable event_counter : shared_counter; event_counter.reset; event_counter.increment (2); assert event_counter.value > 0; -- Example 19.2, Page 588 type shared_counter is protected body variable count : integer := 0; procedure reset is begin count := 0; end procedure reset; procedure increment ( by : integer := 1 ) is begin count := count + by; end procedure increment; impure function value return integer is begin return count; end function value; end protected body shared_counter; -- Example 19.3, Page 589 package shared_counter_pkg is type shared_counter is protected procedure reset; procedure increment ( by : integer := 1 ); impure function value return integer; end protected shared_counter; end package shared_counter_pkg; -- Example 19.3, Page 590 package body shared_counter_pkg is type shared_counter is protected body variable count : integer := 0; procedure reset is ... procedure increment ( by : integer := 1 ) is ... impure function value return integer is begin return count; end function value; end protected body shared_counter; ... end package body shared_counter_pkg; <>.reset; alias duv_event_counter is <>; ... duv_event_counter.increment(4); -- Example 19.4, Page 591 entity two_port_reg is generic ( width : natural ); port ( read_clk : in bit; read_data : out bit_vector(0 to width-1); write_clk : in bit; write_data : in bit_vector(0 to width-1) ); end entity two_port_reg; architecture behavioral of two_port_reg is subtype word is bit_vector(0 to width-1); type protected_reg is protected impure function get return word; procedure set ( new_value : word ); end protected protected_reg; type protected_reg is protected body variable reg : word; impure function get return word is begin return reg; end function get; procedure set ( new_value : word ) is begin reg := new_value; end procedure set; end protected body protected_reg; shared variable reg_store : protected_reg; begin reader : process ( read_clk ) is begin if read_clk then -- on rising edge read_data <= reg_store.get; -- read current value end if; end process reader; writer : process ( write_clk ) is begin if write_clk then -- on rising edge reg_store.set ( write_data ); -- set to new value end if; end process writer; end architecture behavioral; -- Example 19.5, Page 593 package cache_instrumentation is use work.cache_types.all; type shared_counters is protected procedure log_read_miss ( block_number : block_range; is_shared : bit ); procedure log_write_miss ( block_number : block_range ); procedure dump_log ( file log_file : std.textio.text ); end protected shared_counters; shared variable cache_counters : shared_counters; end package cache_instrumentation; package body cache_instrumentation is type shared_counters is protected body type counter_record is record -- counters for a block shared_read_misses, private_read_misses, write_misses : natural; end record counter_record; type counter_array is array ( block_range ) of counter_record; -- instrumentation data structure variable counters : counter_array := (others => (0, 0, 0)); procedure log_read_miss ( block_number : block_range; is_shared : bit ) is begin if is_shared then counters(block_number).shared_read_misses := counters(block_number).shared_read_misses + 1; else counters(block_number).private_read_misses := counters(block_number).private_read_misses + 1; end if; end procedure log_read_miss; procedure log_write_miss ( block_number : block_range ) is begin counters(block_number).write_misses := counters(block_number).write_misses + 1; end procedure log_write_miss; procedure dump_log ( file log_file : std.textio.text ) is use std.textio.all; variable L : line; begin -- write a line of data for each block in the address space for block_number in block_range loop swrite ( L, "Block " ); write ( L, block_number ); swrite ( L, ": shared read misses = " ); write ( L, counters(block_number).shared_read_misses ); ... writeline ( log_file, L ); end loop; end procedure dump_log; end protected body shared_counters; end package body cache_instrumentation; -- Example 19.5, Page 594 architecture behavioral of cache is use work.cache_instrumentation.all; ... begin cache_controller : process is ... -- local variables used by the cache controller begin ... -- if cache miss, record in the instrumentation shared variable if not hit then if read then cache_counters.log_read_miss ( current_block_number, block_is_shared ); else cache_counters.log_write_miss ( current_block_number ); end if; end if; ... end process cache_controller; ... end architecture behavioral; -- Example 19.5, Page 595 architecture system of multiprocessor is ... -- signal declarations begin PE_array : for PE_index in 0 to num_PEs - 1 generate -- a processing element PE : entity work.processor(behavioral) port map ( ... ); -- and its attached level-2 cache L2_cache : entity work.cache(behavioral) port map ( ... ); ... end generate PE_array; -- the instrumentation process that periodically dumps -- recorded counts to the output file log_controller : process is use work.cache_instrumentation.all; begin wait for 10 ms; cache_counters.dump_log ( std.textio.output ); end process log_controller; ... end architecture system; -- Page 596 procedure copy ( variable from : in shared_counter ); procedure copy ( variable from : in shared_counter ) is begin count := from.value; end procedure copy; shared variable a, b : shared_counter; a.copy(b); b.copy(a); ---------------------------------------------------------------- -- 19.2 Uninstantiated Methods in Protected Types ---------------------------------------------------------------- -- Page 597 procedure uninstantiated_name generic ( ... ) parameter ( ... ); type PT is protected ... procedure instance_name is new uninstantiated_name generic map ( ... ); ... end protected PT; shared variable SV : PT; SV.instance_name ( ... ); -- Page 598 procedure uninstantiated_name generic ( ...; formal_generic_subprogram; ... ) parameter ( ... ); type PT is protected method_declaration; procedure instance_name is new uninstantiated_name generic map ( ..., method_name, ... ); ... end protected PT; -- Example 19.6, Page 598 procedure trace_test_vector is generic ( impure function get_test_vector ( vector_time : time ) return test_vector ) parameter ( vector_time : time ) is variable vector : test_vector; use std.textio.all; variable L : line; begin write(L, now); write(L, string'(": ")); vector := get_test_vector(vector_time); ... -- write test vector writeline(output, L); end procedure trace; -- Example 19.6, Page 599 type test_set is protected ... impure function get_vector_for_time ( vector_time : time ) return test_vector; procedure trace_for_time is new trace_test_vector generic map ( get_test_vector => get_vector_for_time ); end protected test_set; shared variable main_test_set, extra_test_set : test_set; main_test_set.trace_for_time(100 ns); extra_test_set.trace_for_time(100 ns); -- Example 19.7, Page 599 procedure output_signed ( value : in signed ) is use std.textio.all; variable L : line; begin write(L, value); writeline(output, L); end procedure output_signed; -- Example 19.7, Page 600 type signed_stimulus_list is protected ... procedure traverse_with_in_parameter generic ( procedure visit ( param : in signed ) ); procedure output_all is new traverse_with_in_parameter generic map ( visit => output_signed ); end protected signed_stimulus_list; shared variable list1 : signed_stimulus_list; ... list1.output_all; variable sum, average : signed(31 downto 0); variable count : natural := 0; procedure accumulate_signed ( value : in signed ) is begin sum := sum + value; count := count + 1; end procedure accumulate_signed; procedure accumulate_all_list1 is new list1.traverse_with_in_parameter generic map ( visit => accumulate_signed ); ... accumulate_all_list1; average := sum / count; -- Example 19.7, Page 601 procedure calculate_average ( variable list : inout signed_stimulus_list variable average : out signed ) is variable sum : signed(average'range); variable count : natural := 0; procedure accumulate_signed ( value : in signed ) is begin sum := sum + value; count := count + 1; end procedure accumulate_signed; procedure accumulate_all is new list.traverse_with_in_parameter generic map ( visit => accumulate_signed ); begin accumulate_all; average := sum / count; end procedure calculate_average; ---------------------------------------------------------------- -- Exercises ---------------------------------------------------------------- -- Exercise 1 shared variable multiply_counter : natural := 0; instrumentation.multiply_counter := instrumentation.multiply_counter + 1; -- Exercise 4 type random_generator is protected impure function next_random return real; impure function next_random ( min, max : real ) return real; impure function next_random ( min, max : integer ) return integer; ... end protected random_generator;