-- ----------------------------------------------------------------
-- client_server_pkg.vhd
--
-- 6/24/2015 D. W. Hawkins (dwh@caltech.edu)
--
-- A simple client/server communications package that uses a
-- global handshake.
--
-- NOTE:
-- I do not recommend using this technique. Using a resolved
-- signal is a much nicer solution.
--
-- This coding style results in errors of the form:
--
-- # ** Error: Cannot drive signal "client_server_req" from procedure "handshake"
-- # ** Error: Cannot drive signal "client_server_req" from procedure "write"
-- # ** Error: Cannot drive signal "client_server_req" from procedure "read"
--
-- which is the same sort of error I saw when trying to wrap the
-- Altera BFM VHDL. What is wrong with driving the global signal
-- in the package from the procedure body? Is that illegal VHDL?
-- You can read a global signal, why not drive one?
--
-- Look in Bergeron ...
--
-- J. Bergeron, "Writing Testbenches: Functional Verification of
-- HDL Models", Kluwer, 2000.
--
-- p241 Sample 6-14 i386sx package uses separate from and to server
-- global signals, but then on p244 his procedures are passed the
-- request and response signals as arguments. p247 Sample 6-21
-- shows an array of request and response signals for multiple
-- BFMs.
--
-- What VHDL rule is the procedure breaking by driving a signal?
-- Is it the fact that the arguments are effectively the
-- sensitivity list?
--
-- Look in Ashenden ...
--
-- P. J. Ashenden, "The Designer's Guide to VHDL", 3rd Ed,
-- Morgan Kaufmann, 2008.
--
-- Ch. 6 Subprograms, p217, 6.2.1 Signal parameters:
-- p220 has a comment that probably applies to procedures in a
-- package, i.e., that assignments statements can only occur
-- to signals passed as parameters.
--
-- VHDL-2008-LRM p36 of PDF "4.2.2.3 Signal parameters"
-- Has comments about assignments to drivers for procedure signal
-- arguments, but nothing about assignments to global signals.
--
-- ----------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;

-- ----------------------------------------------------------------

package client_server_pkg is

	-- Client/server operations
    type client_server_operation_t is (
    	OP_WRITE,
    	OP_READ
    );

	-- Client/server command/response data
	type client_server_data_t is record
		bit  : std_logic; -- request/acknowledge
		op   : client_server_operation_t;
		addr : std_logic_vector(31 downto 0);
		data : std_logic_vector(31 downto 0);
	end record;

	-- Client/server handshake and command/response
	-- via global signals
	signal client_server_req : client_server_data_t;
	signal client_server_ack : client_server_data_t;

	-- Client/server procedures
	procedure write (
		p_addr : in  std_logic_vector(31 downto 0);
		p_data : in  std_logic_vector(31 downto 0)
	);
	procedure read (
		p_addr : in  std_logic_vector(31 downto 0);
		p_data : out std_logic_vector(31 downto 0)
	);
end package;

-- ----------------------------------------------------------------

package body client_server_pkg is

	-- Client/server handshake
	procedure handshake is
	begin
		client_server_req.bit <= '1';
		wait until client_server_ack.bit = '1';
		client_server_req.bit <= '0';
		wait until client_server_ack.bit = '0';
	end procedure;

	-- Client/server communications
	procedure write (
		p_addr : in  std_logic_vector(31 downto 0);
		p_data : in  std_logic_vector(31 downto 0)
	) is
	begin
		client_server_req.op   <= OP_WRITE;
		client_server_req.addr <= p_addr;
		client_server_req.data <= p_data;
		handshake;
	end procedure;

	procedure read (
		p_addr : in  std_logic_vector(31 downto 0);
		p_data : out std_logic_vector(31 downto 0)
	) is
	begin
		client_server_req.op   <= OP_WRITE;
		client_server_req.addr <= p_addr;
		client_server_req.data <= (others => '0');
		handshake;
		p_data := client_server_ack.data;
	end procedure;

end package body;


