---------------------------------------------------------------- -- Chapter 6 Subprograms ---------------------------------------------------------------- ---------------------------------------------------------------- -- 6.1 Procedures ---------------------------------------------------------------- -- Example 6.1, Page 208 procedure average_samples is variable total : real := 0.0; begin assert samples'length > 0 severity failure; for index in samples'range loop total := total + samples(index); end loop; average := total / real(samples'length); end procedure average_samples; -- Page 208 average_samples; -- Example 6.2, Page 209 architecture rtl of control_processor is type func_code is (add, subtract); signal op1, op2, dest : integer; signal Z_flag : boolean; signal func : func_code; ... begin alu : process is procedure do_arith_op is variable result : integer; begin case func is when add => result := op1 + op2; when subtract => result := op1 - op2; end case; dest <= result after Tpd; Z_flag <= result = 0 after Tpd; end procedure do_arith_op; begin ... do_arith_op; ... end process alu; ... end architecture rtl; -- Example 6.3, Page 210 instruction_interpreter : process is variable mem_address_reg, mem_data_reg, prog_counter, instr_reg, accumulator, index_reg : word; ... procedure read_memory is begin address_bus <= mem_address_reg; mem_read <= '1'; mem_request <= '1'; wait until mem_ready; mem_data_reg := data_bus_in; mem_request <= '0'; wait until not mem_ready; end procedure read_memory; begin ... -- initialization loop -- fetch next instruction mem_address_reg := prog_counter; read_memory; -- call procedure instr_reg := mem_data_reg; ... case opcode is ... when load_mem => mem_address_reg := index_reg + displacement; read_memory; -- call procedure accumulator := mem_data_reg; ... end case; end loop; end process instruction_interpreter; -- Example 6.4, Page 211 control_sequencer : process is procedure control_write_back is begin wait until phase1; reg_file_write_en <= '1'; wait until not phase2; reg_file_write_en <= '0'; end procedure control_write_back; procedure control_arith_op is begin wait until phase1; A_reg_out_en <= '1'; B_reg_out_en <= '1'; wait until not phase1; A_reg_out_en <= '0'; B_reg_out_en <= '0'; wait until phase2; C_reg_load_en <= '1'; wait until not phase2; C_reg_load_en <= '0'; control_write_back; -- call procedure end procedure control_arith_op; ... begin ... control_arith_op; -- call procedure ... end process control_sequencer; ---------------------------------------------------------------- -- 6.1.1 Return Statement in a Procedure ---------------------------------------------------------------- -- Example 6.5, Page 212 instruction_interpreter : process is ... procedure read_memory is begin address_bus <= mem_address_reg; mem_read <= '1'; mem_request <= '1'; wait until mem_ready or reset; if reset then return; end if; mem_data_reg := data_bus_in; mem_request <= '0'; wait until not mem_ready; end procedure read_memory; begin ... -- initialization loop ... read_memory; exit when reset; ... end loop; end process instruction_interpreter; ---------------------------------------------------------------- -- 6.2 Procedure Parameters ---------------------------------------------------------------- -- Example 6.6, Page 214 procedure do_arith_op ( op : in func_code ) is variable result : integer; begin case op is when add => result := op1 + op2; when subtract => result := op1 - op2; end case; dest <= result after Tpd; Z_flag <= result = 0 after Tpd; end procedure do_arith_op; do_arith_op ( add ); do_arith_op ( func ); -- Example 6.6, Page 215 procedure do_arith_op ( op : func_code ) is ... -- Example 6.7, Page 215 procedure addu ( a, b : in word32; sum : out word32; overflow : out bit ) is variable carry : bit := '0'; begin for index in sum'reverse_range loop sum(index) := a(index) xor b(index) xor carry; carry := ( a(index) and b(index) ) or ( carry and ( a(index) xor b(index) ) ); end loop; overflow := carry; end procedure addu; -- Example 6.7, Page 216 variable PC, next_PC : word32; variable overflow_flag : bit; ... addu ( PC, X"0000_0004", next_PC, overflow_flag); -- Example 6.8, Page 216 procedure negate ( a : inout word32 ) is variable carry_in : bit := '1'; variable carry_out : bit; begin a := not a; for index in a'reverse_range loop carry_out := a(index) and carry_in; a(index) := a(index) xor carry_in; carry_in := carry_out; end loop; end procedure negate; -- Example 6.8, Page 217 variable op1 : word32; ... negate ( op1 ); ---------------------------------------------------------------- -- 6.2.1 Signal Parameters ---------------------------------------------------------------- -- Example 6.9, Page 218 architecture behavioral of receiver is ... -- type declarations, etc signal recovered_data : bit; signal recovered_clock : bit; ... procedure receive_packet ( signal rx_data : in bit; signal rx_clock : in bit; data_buffer : out packet_array ) is begin for index in packet_index_range loop wait until rx_clock; data_buffer(index) := rx_data; end loop; end procedure receive_packet; begin packet_assembler : process is variable packet : packet_array; begin ... receive_packet ( recovered_data, recovered_clock, packet ); ... end process packet_assembler; ... end architecture behavioral; -- Example 6.10, Page 219 library ieee; use ieee.std_logic_1164.all; architecture top_level of signal_generator is signal raw_signal : std_ulogic; ... procedure generate_pulse_train ( width, separation : in delay_length; number : in natural; signal s : out std_ulogic ) is begin for count in 1 to number loop s <= '1', '0' after width; wait for width + separation; end loop; end procedure generate_pulse_train; begin raw_signal_generator : process is begin ... generate_pulse_train ( width => period / 2, separation => period - period / 2, number => pulse_count, s => raw_signal ); ... end process raw_signal_generator; ... end architecture top_level; ---------------------------------------------------------------- -- 6.2.2 Default Values ---------------------------------------------------------------- -- Example 6.11, Page 221 procedure increment ( a : inout word32; by : in word32 := X"0000_0001" ) is variable sum : word32; variable carry : bit := '0'; begin for index in a'reverse_range loop sum(index) := a(index) xor by(index) xor carry; carry := ( a(index) and by(index) ) or ( carry and ( a(index) xor by(index) ) ); end loop; a := sum; end procedure increment; increment(count, X"0000_0004"); increment(count); increment(count, by => open); ---------------------------------------------------------------- -- 6.2.3 Unconstrained Array Parameters ---------------------------------------------------------------- -- Example 6.12, Page 222 procedure find_first_set ( v : in bit_vector; found : out boolean; first_set_index : out natural ) is begin for index in v'range loop if v(index) then found := true; first_set_index := index; return; end if; end loop; found := false; end procedure find_first_set; variable int_req : bit_vector (7 downto 0); variable top_priority : natural; variable int_pending : boolean; ... find_first_set ( int_req, int_pending, top_priority ); variable free_block_map : bit_vector(0 to block_count-1); variable first_free_block : natural; variable free_block_found : boolean; ... find_first_set ( free_block_map, free_block_found, first_free_block ); -- Example 6.13, Page 223 procedure bv_lt ( bv1, bv2 : in bit_vector; result : out boolean ) is variable tmp1 : bit_vector(bv1'range) := bv1; variable tmp2 : bit_vector(bv2'range) := bv2; begin tmp1(tmp1'left) := not tmp1(tmp1'left); tmp2(tmp2'left) := not tmp2(tmp2'left); result := tmp1 < tmp2; end procedure bv_lt; -- Example 6.14, Page 223 type bv_vector is array (natural range <>) of bit_vector; procedure swap ( a1, a2 : inout bv_array ) is variable temp : a1'subtype; begin assert a1'length = a2'length and a1'element'length = a2'element'length; temp := a1; a1 := a2; a2 := temp; end procedure swap; ---------------------------------------------------------------- -- 6.2.4 Summary of Procedure Parameters ---------------------------------------------------------------- -- Example 6.15, Page 225 procedure p ( f1 : in t1; f2 : in t2; f3 : out t3; f4 : in t4 := v4 ) is begin ... end procedure p; p ( val1, val2, var3, val4 ); p ( f1 => val1, f2 => val2, f4 => val4, f3 => var3 ); p ( val1, val2, f4 => open, f3 => var3 ); p ( val1, val2, var3 ); ---------------------------------------------------------------- -- 6.3 Concurrent Procedure Call Statements ---------------------------------------------------------------- -- Page 225 call_proc : p ( s1, s2, val1 ); call_proc : process is begin p ( s1, s2, val1 ); wait on s1, s2; end process call_proc; -- Example 6.16, Page 226 procedure check_setup ( signal data, clock : in bit; constant Tsu : in time ) is begin if rising_edge(clock) then assert data'last_event >= Tsu report "setup time violation" severity error; end if; end procedure check_setup; check_ready_setup : check_setup ( data => ready, clock => phi2, Tsu => Tsu_rdy_clk ); -- Example 6.17, Page 227 procedure generate_clock ( signal clk : out std_ulogic; constant Tperiod, Tpulse, Tphase : in time ) is begin wait for Tphase; loop clk <= '1', '0' after Tpulse; wait for Tperiod; end loop; end procedure generate_clock; signal phi1, phi2 : std_ulogic := '0'; ... gen_phi1 : generate_clock ( phi1, Tperiod => 50 ns, Tpulse => 20 ns, Tphase => 0 ns ); gen_phi2 : generate_clock ( phi2, Tperiod => 50 ns, Tpulse => 20 ns, Tphase => 25 ns ); ---------------------------------------------------------------- -- 6.4 Functions ---------------------------------------------------------------- -- Example 6.18, Page 228 function limit ( value, min, max : integer ) return integer is begin if value > max then return max; elsif value < min then return min; else return value; end if; end function limit; -- Example 6.18, Page 229 new_temperature := limit ( current_temperature + increment, 10, 100 ); new_motor_speed := old_motor_speed + scale_factor * limit ( error, -10, +10 ); -- Example 6.19, Page 229 function bv_to_natural ( bv : in bit_vector ) return natural is variable result : natural := 0; begin for index in bv'range loop result := result * 2 + bit'pos(bv(index)); end loop; return result; end function bv_to_natural; type rom_array is array (natural range 0 to rom_size-1) of bit_vector(0 to word_size-1); variable rom_data : rom_array; -- Example 6.19, Page 230 data <= rom_data ( bv_to_natural(address) ) after Taccess; ---------------------------------------------------------------- -- 6.4.1 Functional Modeling ---------------------------------------------------------------- -- Page 230 function bv_add ( bv1, bv2 : in bit_vector ) return bit_vector is begin ... end function bv_add; signal source1, source2, sum : bit_vector(0 to 31); adder : sum <= bv_add(source1, source2) after T_delay_adder; ---------------------------------------------------------------- -- 6.4.2 Pure and Impure Functions ---------------------------------------------------------------- -- Example 6.20, Page 231 network_driver : process is constant seq_modulo : natural := 2**5; subtype seq_number is natural range 0 to seq_modulo-1; variable next_seq_number : seq_number := 0; ... impure function generate_seq_number return seq_number is variable number : seq_number; begin number := next_seq_number; next_seq_number := (next_seq_number + 1) mod seq_modulo; return number; end function generate_seq_number; begin -- network_driver ... new_header := pkt_header'( dest => target_host_id, src => my_host_id, pkt_type => control_pkt, seq => generate_seq_number ); ... end process network_driver; ---------------------------------------------------------------- -- 6.4.3 The Function now ---------------------------------------------------------------- -- Page 232 impure function now return delay_length; -- Example 6.21, Page 232 hold_time_checker : process ( clk, d ) is variable last_clk_edge_time : time := 0 fs; begin if rising_edge(clk) then last_clk_edge_time := now; end if; if d'event then assert now - last_clk_edge_time >= Thold_d_clk report "hold time violation"; end if; end process hold_time_checker; ---------------------------------------------------------------- -- 6.5 Overloading ---------------------------------------------------------------- -- Page 233 procedure increment ( a : inout integer; n : in integer := 1 ) is ... procedure increment ( a : inout bit_vector; n : in bit_vector := B"1" ) is ... procedure increment ( a : inout bit_vector; n : in integer := 1 ) is ... variable count_int : integer := 2; variable count_bv : bit_vector (15 downto 0) := X"0002"; increment ( count_int, 2 ); increment ( count_int ); -- Page 234 increment ( count_bv, X"0002"); increment ( count_bv, 1 ); increment ( count_bv ); ---------------------------------------------------------------- -- 6.5.1 Overloading Operator Symbols ---------------------------------------------------------------- -- Page 234 function "+" ( left, right : in bit_vector ) return bit_vector is begin ... end function "+"; variable addr_reg : bit_vector(31 downto 0); ... addr_reg := addr_reg + X"0000_0004"; -- Page 235 function "abs" ( right : in bit_vector ) return bit_vector is begin ... end function "abs"; variable accumulator : bit_vector(31 downto 0); ... accumulator := abs accumulator; -- Example 6.22, Page 235 library ieee; use ieee.std_logic_1164.all; entity reg_ctrl is port ( reg_addr_decoded, rd, wr, io_en, cpu_clk : in std_ulogic; reg_rd, reg_wr : out std_ulogic ); end entity reg_ctrl; -------------------------------------------------- architecture bool_eqn of reg_ctrl is begin rd_ctrl : reg_rd <= reg_addr_decoded and rd and io_en; rw_ctrl : reg_wr <= reg_addr_decoded and wr and io_en and not cpu_clk; end architecture bool_eqn; -- Page 236 function "??" ( right : integer ) return boolean is begin return right /= 0; end function "??"; variable m : integer; ... if m then ... end if; ---------------------------------------------------------------- -- 6.6 Visibility of Declarations ---------------------------------------------------------------- -- Example 6.23, Figure 6.1, Page 237 architecture arch of ent is type t is ...; signal s : t; procedure p1 ( ... ) is variable v1 : t; begin v1 := s; end procedure p1; begin -- arch proc1 : process is variable v2 : t; procedure p2 ( ... ) is variable v3 : t; begin p1 ( v2, v3, ... ); end procedure p2; begin -- proc1 p2 ( v2, ... ); end process proc1; proc2 : process is ... begin -- proc2 p1 ( ... ); end process proc2; end architecture arch; -- Example 6.24, Page 238 architecture behavioral of cache is begin behavior : process is ... procedure read_block( start_address : natural; entry : out cache_block ) is variable memory_address_reg : natural; variable memory_data_reg : word; procedure read_memory_word is begin mem_addr <= memory_address_reg; mem_read <= '1'; wait until mem_ack; memory_data_reg := mem_data_in; mem_read <= '0'; wait until not mem_ack; end procedure read_memory_word; begin -- read_block for offset in 0 to block_size - 1 loop memory_address_reg := start_address + offset; read_memory_word; entry(offset) := memory_data_reg; end loop; end procedure read_block; begin -- behavior ... read_block( miss_base_address, data_store(entry_index) ); ... end process behavior; end architecture behavioral; -- Figure 6.2, Page 240 procedure p1 is variable v : integer; procedure p2 is variable v : integer; begin -- p2 ... v := v + 1; ... end procedure p2; begin -- p1 ... v := 2 * v; ... end procedure p1; ---------------------------------------------------------------- -- Exercises ---------------------------------------------------------------- -- Exercise 4 procedure stimulate ( signal target : out bit_vector; delay : in delay_length := 1 ns; cycles : in natural := 1 ) is ... -- Exercise 5 procedure shuffle_bytes ( signal d_in : in std_ulogic_vector(0 to 15); signal d_out : out std_ulogic_vector(0 to 15); signal shuffle_control : in std_ulogic; prop_delay : delay_length ) is ... swapper : shuffle_bytes ( ext_data, int_data, swap_control, Tpd_swap ); -- Exercise 6 function approx_log_2 ( a : in bit_vector ) return positive is ... -- Exercise 8 increment ( count_bv, -1 ); increment ( count_int ); increment ( count_int, B"1" ); increment ( count_bv, 16#10# ); -- Exercise 9 architecture behavioral of computer_system is signal internal_data : bit_vector(31 downto 0); interpreter : process is variable opcode : bit_vector(5 downto 0); procedure do_write is variable aligned_address : natural; begin ... end procedure do_write; begin ... end process interpreter; end architecture behavioral; -- Exercise 22 type table is array (0 to 1023) of real;